0

I'd like to be able to "somehow" create a dynamic array that would still let me build its elements using the new operator. Here's what I'd like to achieve:

A* a = new A[3]; //or any equivalent syntax 
new (&a[0]) A(myparams1); //placement new on first slot 
new (&a[1]) A(myparams2, ...); //placement new on 2nd slot 
new (&a[2]) A(myparams3, ...); //placement new on 3rd slot
delete[] a; //correct deletion of all elements

I'm aware that this code would work (minus the 3 elements overwritten), but I'd like to avoid creating 3 default a elements in the first call to new[]. I am assuming here that I will always place 3 elements before calling delete[]. I'm thinking such a thing can be achieved by using intelligent calls to A::operator new[] but I'm not sure how. Does anyone have any idea? it's mostly for curiosity

lezebulon
  • 7,607
  • 11
  • 42
  • 73

3 Answers3

3

You just get raw memory instead:

void* mem = ::operator new(capacity * sizeof(A));

This is required to be aligned for any type, including an array of A's. Now you can construct in it:

for (std::size_t i = 0; i < capacity; ++i)
{
    void* addr = static_cast<char*>(mem) + i * sizeof(A);
    new (addr) A(x, y, z, ...);
}

Destruction requires you explicitly invoke it:

for (std::size_t i = 0; i < capacity; ++i)
{
    void* addr = static_cast<char*>(mem) + i * sizeof(A);
    static_cast<A*>(addr)->~A();
}

And now you can free the raw memory:

::operator delete(mem);

Note that none of this is exception-safe. It's also what std::vector<A> does, check out the code.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • thanks, this looks fine indeed. I'm just wondering if there isn't a variant for arrays? I'm thinking this would be the perfect time to use ::operator new[] and ::operator delete[] – lezebulon May 11 '12 at 22:11
  • @lezebulon: If you want a chunk of `x` bytes, you should just use `::operator new` (or kin). If you want `x` bytes *in an array*, then sure, use `::operator new[]`. But note that's not what we want here, the array is just unnecessary overhead. – GManNickG May 11 '12 at 22:12
  • I'm not sure I understand, what would using ::operator new[] change? I'd be tempted to use it since I'm allocating for an array of objects – lezebulon May 11 '12 at 22:21
  • 1
    @lezebulon: You can use it just fine, it just doesn't match conceptually. You *are not* allocating an array during that `::operator new` call, you're allocating a chunk of memory. – GManNickG May 11 '12 at 22:23
2

Use operator new.

A a* = (A*) ::operator new(sizeof(A) * 3);
new (&a[0]) A(/* whatever */);
//do stuff
a[0].~A();
::operator delete(a);

Pay careful attention to manually calling the destructors. When using placement new the destructor is not called automagically so it's up to you.

Stephen Newell
  • 7,330
  • 1
  • 24
  • 28
1

You can create array of pointers.

A ** a = new A*[3]
a[0] = new A;
a[1] = new A;
a[2] = new A;

You need to call delete on each allocated element

delete a[2];
delete a[1];
delete a[0];

And to delete array itself delete[] a;

mip
  • 8,355
  • 6
  • 53
  • 72