Search code examples
c++new-operatorplacement-new

Using operator new and placement new to create a dynamic array of non-default constructible objects


I am new to placement new so I wanted to separate allocation from initialization using it along operator new to allocate and construct an array of my user-defined type class Foo.

here is what I've tried:

struct Foo{
    Foo(int x) : x_(x){
        std::cout << "Foo(int)\n";
    }
    ~Foo(){
        std::cout << "~Foo()\n";
    }
    int x_ = 0;
};

int main(){

    Foo* pf = static_cast<Foo*>(operator new[](10 * sizeof(Foo) ) );

    for(int i  = 0; i != 10; ++i)
        new(pf + i)Foo(i * 7);

    for(int i = 0; i != 10; ++i)
        std::cout << pf[i].x_ << ", ";
    std::cout << '\n';

    for(int i = 0; i != 10; ++i)
        pf[i].~Foo();

    operator delete[](pf);

}
  • The code looks to work fine so please guide me if I've missed something. And is this similar to how class allocator works? (separate allocation from initialization).

Solution

  • please guide me if I've missed something.

    Seems fine for Foo. But more generally, the approach isn't exception safe. If one of the class constructors throw, then your allocation leaks and the previously constructed objects won't be destroyed.

    And is this similar to how class allocator works?

    Quite similar. A few differences:

    • std::allocator<T>::allocate uses ::operator new(std::size_t, std::align_val_t) and std::allocator<T>::deallocate calls ::operator delete(void*, std::align_val_t) since C+++17. This is needed to support over-aligned types.
    • Technically, you never start lifetime of an array. This isn't a big problem in practice. There isn't any practical way to create dynamic arrays in reused memory. Although, since C++20 std::allocator<T>::allocate actually does start the lifetime of an array of T (without starting the lifetime of the objects). There's technically no way to implement that in standard C++ for non-trivial types.