aligned_storage
, placement new
and explicit destructor calls to the rescue!
enum State { Alive, Dead, Unused };
template<class T> struct Atom
{
typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type impl;
T& data() { return *reinterpret_cast<T*>(&impl); }
T const& data() const { return *reinterpret_cast<T*>(&impl); }
int index, counter;
State state;
template<typename... V>
void create(V&&... args)
{
new(static_cast<void*>(&impl))T(std::forward<V>(args)...);
state = Alive;
}
void destroy() { data().~T(); state = Unused; }
~Atom() { if(state != Unused) destroy(); }
Atom(Atom const& other)
: index(other.index),
counter(other.counter),
state(other.state)
{
if(state != Unused)
new(static_cast<void*>(&impl))T(other.data());
}
Atom(Atom&& other)
: index(other.index),
counter(other.counter),
state(other.state)
{
if(state != Unused)
new(static_cast<void*>(&impl))T(std::move(other.data()));
}
};
The basic idea is to start with providing properly aligned uninitialized storage. Then, when you whish to create an object, a variadic template forwards all your arguments to a placement new expression, which will basically call the constructor on that storage. Finally, when you destroy it (or the destructor of Atom
is called while it is not yet Unused
again), the destructor is called so that the memory does not represent an object anymore.
The humongous copy and move constructors are needed, so that copies will map to copies of the T
s correctly. Writing assignment operators has been omitted for brevity (such as it is).