go to start Ss W5
|home |print view |recent changes |changed April 1, 2016 |
exact
|You are 54.81.139.56 <- set your identity!

Sections: not_on_heap | simple_value_holder | A more elaborate value holder allowing move-only types |

Here is are some code examples from the lecture.

Do you find the bugs in the details?

not_on_heap ^

The following class tries to prohibit heap allocation:

struct not_on_heap {
	bool valid() const {
		return true;
	}
    static void* operator new(std::size_t sz)
    {
    	throw std::bad_alloc{};
    }
    static void* operator new[](std::size_t sz)
    {
    	throw std::bad_alloc{};
    }
    static void operator delete(void *ptr) noexcept  {
    	// do nothing, never called, but should come in pairs
    }
	static void operator delete[](void *ptr) noexcept {
    	// do nothing, never called, but should come in pairs
    }
};

simple_value_holder ^

The following class provides a simple value holder for different copyable types. Usage requires to extract the correct type (which is not checked).

It is used to demonstrate placement new and calling destructor explicitly.

struct simple_holder{
	simple_holder()=default;
	template <typename T>
	simple_holder(T  const &value)
	:pv{new char[sizeof(T)]}
	,del{make_deleter<T>()}
	{
		new(pv)T{value};
	}
	~simple_holder(){
		del(pv);
		delete[]pv;
	}
	simple_holder(simple_holder const &)=delete;
	simple_holder(simple_holder &&rhs) noexcept:simple_holder{}{
		std::swap(pv,rhs.pv);
		std::swap(del,rhs.del);
	}
	explicit operator bool() const { return pv != nullptr;}
	void clear() { del(pv); delete pv; pv=nullptr;}
	template <typename T>
	T const & get() const {
		if (pv) return *reinterpret_cast<T const *>(pv);
		throw bad_get<T>{};
	}
	template <typename T>
	simple_holder& operator=(T  const & val){
		del(pv);
		delete[] pv;
		pv=new char[sizeof(T)];
		new(pv)T{val};
		del=make_deleter<T>();
		return *this;
	}
	simple_holder& operator=(simple_holder const &rhs)=delete; // would need to memorize size as well
	simple_holder& operator=(simple_holder &&rhs){
		del(pv);
		del=[](char *){};
		delete[] pv;
		pv=nullptr;
		std::swap(pv,rhs.pv);
		std::swap(del,rhs.del);
		return *this;
	}

private:
	char *pv{};
	using DELTYPE=void(*)(char *);
	DELTYPE del{[](char *){}}; // no op
	template <typename T>
	static DELTYPE make_deleter(){
		return [](char *p){if(p)reinterpret_cast<T*>(p)->~T();};
	}
};

A more elaborate value holder allowing move-only types ^

template <typename T>
struct bad_get:std::logic_error{
	bad_get():
		logic_error{ typeid(T).name() }{}
};
namespace detail{
auto const no_op_del=[](char *)noexcept{};
}


struct value_holder{
	value_holder()=default;
	template <typename T>
	value_holder(T  &&value)
	:pv{allocate(std::move(value))}
	,del{make_deleter<T>()}
	{}
	value_holder(value_holder const &)=delete;
	value_holder(value_holder &&rhs) noexcept:value_holder{}{
		std::swap(pv,rhs.pv);
		std::swap(del,rhs.del);
	}
	~value_holder(){
		del(pv);
		delete[] pv;
	}
	explicit operator bool() const { return pv != nullptr;}
	void clear() { del(pv); delete pv; pv=nullptr;}
	template <typename T>
	T const & get() const {
		if (pv) return *reinterpret_cast<T const *>(pv);
		throw bad_get<T>{};
	}
	template <typename T>
	value_holder& operator=(T  && val){
		del(pv);
		del=detail::no_op_del; // ensure an exception won't break this
		delete[] pv;
		pv=nullptr;
		pv=allocate(std::move(val));
		del=make_deleter<T>();
		return *this;
	}
	value_holder& operator=(value_holder const &rhs)=delete;
	value_holder& operator=(value_holder &&rhs){
		del(pv);
		del=detail::no_op_del;
		delete[] pv;
		pv=nullptr;
		std::swap(pv,rhs.pv);
		std::swap(del,rhs.del);
		return *this;
	}

private:
	char * pv{};
	using DELTYPE=void(*)(char *);
	DELTYPE del{detail::no_op_del}; // no op
	template <typename T>
	static char *allocate(T && value){
		auto p=new char[sizeof(std::decay_t<T>)];
		new (p) T{std::move(value)};
		return p;
	}
	template <typename T>
	static DELTYPE make_deleter(){
		return [](char *p)noexcept{if(p)reinterpret_cast<std::decay_t<T>*>(p)->~T();};
	}
};


|home |print view |recent changes |changed April 1, 2016 |
exact
|You are 54.81.139.56 <- set your identity!

Ss W5
go to start