C++“新”内存分配

Posted

技术标签:

【中文标题】C++“新”内存分配【英文标题】:C++ "new" memory allocation 【发布时间】:2013-12-05 21:06:42 【问题描述】:

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

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;

工作正常。

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

【问题讨论】:

最好以较小的批量分配动态内存。你的记忆越碎片化,你的新记忆失败的机会就越大。 你为什么不直接使用std::vector&lt;BaseClass&gt; 【参考方案1】:

首先,如果你使用一个展示位置new,那么你需要显式调用析构函数

buf[var].~BaseClass();

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

所以你应该做类似的事情

::operator delete(buf);

【讨论】:

【参考方案2】:

Placement new 不分配内存,它只是调用你给它的内存位置的构造函数。因此,您无需删除单个项目。而不是

delete &buf[var];

试试这个,它调用析构函数而不释放内存:

buf[var].~BaseClass();

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

【讨论】:

另见this post。【参考方案3】:

您使用的是delete,但没有对应的new。使用placement new 在先前分配的内存中构造对象不需要成对使用delete 运算符。相反,placement new 应该与显式析构函数调用配对。由于您直接调用全局 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&lt;BaseClass*&gt;

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

请确保不要对使指针无效的原始向量做任何事情。你可以移动它,但不要复制它然后破坏原件。

【讨论】:

我需要一个指向数组元素的指针。比 - 如果我将 std::vector buf 放在另一个 std::vector 中 - 我会松开那个指针。所以我需要 std::vector - 所以指针指向正确的位置,即使我复制了 std::vector。但是,如果要填充 std::vector,我每次都会做“新”——我会得到很强的性能惩罚。为了避免这种情况,我正在尝试这种方法 - 制作大量对象,然后将它们放入向量中。 @tower120 此方法使用单个分配来创建“大量对象”,就像您自己的代码一样。只要您不采取措施使它们无效,就可以使用指向这些对象的指针。你不能复制向量,就像你不能复制你在示例代码中分配的数组一样。 非常有趣的解决方案。谢谢,但如果你愿意,我需要更多建议。我想将像 Point(10, 12), Point(20, 32) 这样的数组传递给对象。但我还需要传递堆对象。因此,假设我的班级中有 2 个“推送”函数,一个用于 std::vector,另一个用于 std::vector。就我而言,只做一些 BaseClass* 的 poolFactory 并在我的班级中只使用 std::vector 不是更好吗?在这种情况下 Point(10, 12), Point(20, 32) 看起来像 pool.get(10,12), pool.get(20,32)。 @tower120 恐怕我没有足够的上下文来理解这个问题。也许您应该发布另一个问题,说明您如何使用这个对象池。

以上是关于C++“新”内存分配的主要内容,如果未能解决你的问题,请参考以下文章

C++ 中 vector 如何实现内存分配

C++ new的时候,为啥会存在内存分配会失败的情况?啥导致的呢?

指针在删除它并在c ++中再次分配新内存后是不是获得相同的内存地址?

C++ 动态内存分配与结构中的数组

设计模式之争:新分配内存还是内存池?(含评测)

C++中内存分配问题