3

Is there an accepted idiom for allocating the backing store for an object in-place but not initializing it? Here's my naive solution:

#include <utility>

template<typename T> 
union Slot {
    T inst;

    Slot() {}
    ~Slot() {}

    template<typename... Args>
    T* init(Args&&... args) { return new(&inst) T(std::forward<Args>(args) ...); }
    void release() { inst.~T(); }
};

My immediate use case is for an object pool, but it would also be more generally useful.

Max
  • 101
  • 1
  • 4
  • I think what you want is called [placement new](http://en.wikipedia.org/wiki/Placement_syntax). – TypeIA Feb 14 '14 at 20:56
  • @dvnrrs He's using placement new. This code looks fine to me. – user3286380 Feb 14 '14 at 20:56
  • @user3286380 indeed... sorry. I didn't look that closely at the code. What's the question then? There are many ways to allocate memory. – TypeIA Feb 14 '14 at 20:58
  • How about `char inst[sizeof(T)];`? Or, in C++11, `alignas(T) char inst[sizeof(T)];`? – Adam H. Peterson Feb 14 '14 at 20:59
  • @dvnrrs I think the question was if his solution is OK. – user3286380 Feb 14 '14 at 20:59
  • @AdamH.Peterson members in unions with constructors aren't initialized anyway so no need for a `char` buf I believe. – user3286380 Feb 14 '14 at 20:59
  • The obvious problems with the solution the OP gives are that it requires `T` to be default-constructable, actually creates an instance of `T` on constructed, and then ends the lifetime of that `T` without calling its destructor by constructing a new `T` over top of it. It also has exception safety problems if the construction of the new `T` fails, since the old `T` will be destroyed by `Slot`'s own destructor after having been clobbered. – Adam H. Peterson Feb 14 '14 at 21:01
  • you cannot use non-POD types in `union`. – qehgt Feb 14 '14 at 21:01
  • @qehgt in C++11 you can. – user3286380 Feb 14 '14 at 21:02
  • @AdamH.Peterson I don't think members of unions are constructed when the union is constructed. If they are, how would it pick which one? The exception safety is a valid point though. – user3286380 Feb 14 '14 at 21:02
  • @user3286380, good catch. Didn't notice the `union` there. But as @qehgt observes, you can't use non-PODs in unions, so the only constructors it can have are trivial compiler-generated constructors (nothing/zero-initialize for default construct, and bitwise copy for copy-construct). That limits the utility of this solution significantly. – Adam H. Peterson Feb 14 '14 at 21:03
  • @AdamH.Peterson see my response to qehgt. – user3286380 Feb 14 '14 at 21:04
  • If that's the context, this question should probably be tagged with `c++11`. – Adam H. Peterson Feb 14 '14 at 21:05
  • And what about using an `allocator` object where Memory allocation and object construction are seperated. – sleepy1771 Feb 14 '14 at 21:07
  • @AdamH.Peterson his union has a constructor and destructor, so it must be. – user3286380 Feb 14 '14 at 21:08

1 Answers1

4

In C++11 you can use std::aligned_storage (see also ):

template<typename T> 
struct Slot {
    typename std::aligned_storage<sizeof(T)>::type _storage;

    Slot() {}
    ~Slot() { 
       // check if destroyed!
       ...
    }

    template<typename... Args>
    T* init(Args&&... args) { 
        return new(address()) T(std::forward<Args>(args) ...); 
    }

    void release() { (*address()).~T(); }

    T* address()  {
        return static_cast<T*>(static_cast<void*>(&_storage));
    }
};
CouchDeveloper
  • 18,174
  • 3
  • 45
  • 67
  • @Max Notice that this class as it stands can be dangerous to use! You should make it more safe and more convenient to use ;) – CouchDeveloper Feb 14 '14 at 21:17
  • It's a private inner-type, at least, so in principle the danger only lurks behind the interface. – Max Feb 14 '14 at 21:19