2

I want to allocate memory for a huge bulk of objects. Then construct them one by one. So I do the following:

BaseClass* buf = static_cast<BaseClass*> (::operator new (sizeof(BaseClass[5])));
for (int var = 0; var < 5; ++var) {
    new (&buf[var]) BaseClass(var);
}

And everything seems ok. But when I add delete:

BaseClass* buf = static_cast<BaseClass*> (::operator new (sizeof(BaseClass[5])));
for (int var = 0; var < 5; ++var) {

    new (&buf[var]) BaseClass(var);

    // ... do something

    delete &buf[var];
}

I got "segmentation fault" error. On second iteration (on constructor). At the same time

 delete [] buf;

works fine.

So the question is - why this?

tower120
  • 5,007
  • 6
  • 40
  • 88

3 Answers3

4

Placement new doesn't allocate memory, it just calls the constructor for the memory location you gave it. So you don't need to delete the individual items. Instead of

delete &buf[var];

Try this, which calls the destructor without freeing memory:

buf[var].~BaseClass();

Note that you still need to use ::operator delete on the whole chunk of memory, just not on the individual objects.

parkovski
  • 1,503
  • 10
  • 13
4

First of all if you use a placement new then you will need to call destructor explicitly

buf[var].~BaseClass();

Then you can delete just things that have been allocated with a new, while &buf[0] works since it's the address returned by the placement new, &buf[1] has not been directly allocated by the memory manager through ::operator new. You can't free them one by one.

So you should do something like

::operator delete(buf);
Jack
  • 131,802
  • 30
  • 241
  • 343
2

You're using delete without a corresponding new. Using placement new to construct objects in previously allocated memory does not require a paired use of the delete operator. Instead placement new should be paired with explicit destructor calls. Since you're calling the global operator new function directly, you should be pairing that with a direct call to the global operator delete function, rather than using the delete operator at all.

However none if this is necessary for what you've described. The following is much easier:

std::vector<BaseClass> buf;
buf.reserve(5);

for (int var = 0; var < 5; ++var) {
    buf.emplace_back(var);
}

After you have this collection of objects you can put pointers to them into a std::vector<BaseClass*>:

std::vector<BaseClass*> buf2;
buf2.reserve(buf.size());
std::transform(std::begin(buf), std::end(buf), std::back_inserter(buf2),
               std::addressof<BaseClass>);    

Just be sure not to do anything to the original vector that invalidates the pointers. You can move it, but don't copy it and then destroy the original.

bames53
  • 86,085
  • 15
  • 179
  • 244
  • I need a pointer to element in array. Than - if I put std::vector buf inside another std::vector - I'll loose that pointer. So I need std::vector - so pointers point to correct place, even if I copy the std::vector. But if to fill std::vector, I will do each time "new" - I'll get strong perfomance penalty. To avoid this I'm trying this approach - making a bulk of objects and than put them into vector. – tower120 Dec 05 '13 at 22:15
  • @tower120 This method uses a single allocation to create 'a bulk of objects' just as your own code does. You can use pointers to these objects as long as you don't do things to invalidate them. You can't copy the vector, just like you can't copy the array you allocate in your example code. – bames53 Dec 06 '13 at 04:07
  • Very interesting solution. Thank you, but if you will, I need one more advice. I want to pass array like {Point(10, 12), Point(20, 32)} into the object. But I also need to pass heap objects. So lets say I have 2 "push" functions in my class, one for std::vector, another for std::vector. Is it not better, in my case, just do some poolFactory of BaseClass*, and, in my class, work just with std::vector ? In this case {Point(10, 12), Point(20, 32)} will look like {pool.get(10,12), pool.get(20,32)}. – tower120 Dec 06 '13 at 13:40
  • @tower120 I'm afraid I don't have enough context to understand that question. Perhaps you should post another question showing how you're using this pool of objects. – bames53 Dec 06 '13 at 14:50