Reputation: 5265
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?
Upvotes: 2
Views: 298
Reputation: 88215
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.
Upvotes: 2
Reputation: 1523
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.
Upvotes: 4
Reputation: 133609
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);
Upvotes: 4