C++ "new"内存分配

C++ "new" memory allocation

本文关键字:分配 内存 new C++      更新时间:2023-10-16

我想为大量对象分配内存。然后一个接一个地建造。所以我做了以下事情:

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

一切似乎都很好。但当我添加删除时:

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];
}

我犯了"分段错误"。在第二次迭代时(在构造函数上)。同时

 delete [] buf;

工作良好。

所以问题是——为什么会这样?

首先,如果使用放置new,则需要显式调用析构函数

buf[var].~BaseClass();

然后,您可以只删除已经用new分配的东西,而&buf[0]工作,因为它是放置new返回的地址,&buf[1]没有由内存管理器通过::operator new直接分配。你不能一个接一个地解放他们。

所以你应该做一些类似的事情

::operator delete(buf);

Placement new不分配内存,它只调用您给它的内存位置的构造函数。因此,您不需要删除单个项。代替

delete &buf[var];

试试这个,它在不释放内存的情况下调用析构函数:

buf[var].~BaseClass();

请注意,您仍然需要在整个内存块上使用::operator delete,只是不需要在单个对象上使用。

您使用的delete没有相应的new。使用placement new在先前分配的内存中构造对象不需要成对使用delete运算符。相反,placementnew应该与显式析构函数调用成对出现。由于您直接调用全局operator new函数,因此应该将其与对全局operator delete函数的直接调用配对,而不是使用delete运算符。

但是,如果这对于您所描述的内容是必要的,则不需要。以下操作要简单得多:

std::vector<BaseClass> buf;
buf.reserve(5);
for (int var = 0; var < 5; ++var) {
    buf.emplace_back(var);
}

在您有了这个对象集合之后,您可以将指向它们的指针放入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>);    

只是要确保不要对原始向量执行任何使指针无效的操作。你可以移动它,但不要复制它,然后销毁原来的。