tower120
tower120

Reputation: 5265

C++ "new" memory allocation

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

Answers (3)

bames53
bames53

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

parkovski
parkovski

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

Jack
Jack

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

Related Questions