C++ STL 内存管理:堆栈还是堆?

Posted

技术标签:

【中文标题】C++ STL 内存管理:堆栈还是堆?【英文标题】:C++ STL Memory Management: Stack or Heap? 【发布时间】:2012-07-28 09:49:25 【问题描述】:

通常,当我使用非本地范围内的 STL 对象时,我会存储指向我想要存储的数据的指针。比如

std::vector<MyStruct*> 

当需要清理向量时,我会检查并删除所有内容。我最近注意到这并不像我想象的那样是必要的。无论出于何种原因,我一直认为 STL 类将数据存储在堆栈上,而我现在认为它是在堆上分配数据的。它是否正确?将对象存储为指针以减少复制时间是唯一真正的好处吗?

【问题讨论】:

std::vector&lt;Shape *&gt; 可以存储Circle *std::vector&lt;Shape&gt; 不能存储Circle 每个动态容器中的每个对象始终是无条件的动态对象,其生命周期由容器管理。可配置的是内存分配策略,但这并不重要。请记住,C++ 将内存分配和对象创建作为两个不同的概念和职责范围分开。 【参考方案1】:

标准容器通过分配器对象分配内存,其类型作为模板参数传递。如果你没有传递其他任何东西,那就是std::allocator&lt;T&gt;,它将使用new 来分配内存。

底线:您可以强制他们以几乎任何您想要的方式分配内存,但默认情况下它将来自免费存储。

如果你真的想要一个指针容器,容器将拥有指针对象(例如,当对象被销毁时会自动删除它们),你可能想看看 Boost Pointer Containers。

【讨论】:

【参考方案2】:

使用指针来减少复制时间真正的好处。想想所有可以通过它改进的向量操作 - 例如排序。

另一个真正的好处(如上面评论中所述)是这允许您使用多态性并将相关对象存储在同一向量中。标量对象(非指针)无法做到的事情。

您将数据存储在堆栈还是堆上并不会影响移动该对象的成本(嗯...确实如此,但通常可以忽略不计,并且与本次讨论无关)。

当您将指向对象的指针存储在 STL 向量中时,该向量不会取得对象的所有权。您仍然需要尽职调查并在不再需要它们时清理它们。

【讨论】:

【参考方案3】:

[...] 而我现在认为它将它分配在堆上。这是正确的吗?

是的。如果将向量声明为:

std::vector<MyStruct*> v;

那么您基本上将指针存储在向量中,因此向量将分配内存来存储 指针,而不是指针指向的对象。所以当析构函数运行时,向量将释放它已经分配的内存,它不会释放指针本身的内存,即它不会释放存储在向量中的指针指向的内存。

但是,如果你这样声明:

std::vector<MyStruct> v;

然后你自己存储对象,所以向量将分配内存来存储对象,并在析构函数运行时释放它。

【讨论】:

【参考方案4】:

当需要清理向量时,我会检查并删除 一切。我最近注意到这不像我一样有必要 以为是。

不要假设。如果向量中的指针指向动态分配的内存,那么您需要删除该内存,因为向量不会为您执行此操作。

例如,如果您的代码属于该类型

 MyStruct* pNewStruct = new MyStruct;
 myVector.push_back(pNewStruct);

 ...
 ...

 myVector.clear();

您有内存泄漏,因为您没有专门删除分配给添加到向量中的每个元素的内存。作为动态数组的一部分,向量释放了它在自身内部分配的内存,但这只是释放了指针数组,而不是它们指向的内存

【讨论】:

以上是关于C++ STL 内存管理:堆栈还是堆?的主要内容,如果未能解决你的问题,请参考以下文章

C++ STL 问题:分配器

用于位图管理的 C++ STL 类

c++堆栈的各自大小,堆和栈的各自定义

智能指针类模板

第61课 智能指针类模板

c++师傅领进门,修行靠个人第六篇:内存管理