内存管理和std::allocator

6

在审查我的代码时,我发现我使用了一些“丑陋”的结构,在一个名为“map”的类中,我有一个包含“data”类的向量:

std::vector<PointerToHUGEClass> vector;

指针PointerToHUGEClass就像其名称所描述的那样。 (尽管指向的对象也由map类拥有,并在构造函数中使用“new”参数创建)。目前这很好用。但是我仍然觉得这更像是一种解决方法。

我使用“PointerToHUGEClass”的唯一原因是,我希望确保该对象未从堆栈中声明。不过,在我理解allocater之前就已经做出了这个决定。现在我感觉应该由分配器来确保内存未从堆栈中声明。

我的问题:

  • 我是否正确地认为分配器负责来自项目的内存管理?(并确保它是从堆栈/自由存储区/堆/任何其他地方声明的)
  • std :: allocator是做什么的? - 它是从堆栈还是从堆中声明的?
  • (上一个问题的后续):如果我将从堆栈中声明的项复制到数据结构中,它是否仍然在堆中声明?

再次感谢, paul23


@Simone:嗯,那段代码应该写成std::vector<PointerToHUGEClass>或者std::vector<HUGEClass*>。感谢你的指出。(虽然这并不会改变我的问题,因为这是我已经思考了一年的一般性问题) - paul23
2个回答

10
  • 我是否正确地认为分配器是负责从项中进行内存管理的?(并确保它是从栈/自由存储区/堆/任何地方声明的)

不对。分配器只是对newdelete的包装,通常负责决定在哪里分配内存。调用allocate, deallocate, constructdestruct 的责任是分配器的用户(也就是这里的std::vector)。从你的角度来看,这将是自动的,这毕竟是最重要的。

  • std::allocator是做什么的? - 它会从堆栈还是堆中声明?

std::allocator被指定使用::operator new(size_t) 进行分配,因此它取决于全局new运算符的定义。一般来说,这意味着使用堆。而栈则用于具有自动存储期的对象。

  • (来自上一个问题的后续问题):如果我将在栈中声明的项目复制到数据结构中,它是否仍在堆中声明?

如果您复制一个项目,则会将副本分配到复制它的位置。这意味着从栈复制项到堆,现在有两个对象的副本,这意味着对一个副本的更改不会反映在另一个副本上。

但要注意,我们谈论的是默认复制模式,即浅层复制。如果您复制一个对象,那么它将被复制得很好;如果您复制指针,则只复制指针,而不是指向的数据。


1
你能告诉我 std::allocator 被指定使用 ::operator new 的位置吗?我在标准中找不到参考文献。 - Simone
@Simone:我参考了Steve Jessop在stackoverflow上的这个答案https://dev59.com/gW855IYBdhLWcg3ww3Sa#4159686,但是据我所知它并没有涉及到C++0x的最终草案(20.4只是关于元组的)。我在这个草案中也没有找到相关内容。我已经编辑了运算符的签名以使其更加精确。 - Matthieu M.

0

你的答案:

  • 是的,你说得对。不管怎样,如果容器的模板类型是指针,就像你的情况一样,容器将为指针分配/释放内存,而不是指针所指向的对象!

  • 这取决于实现,在标准的$20.2.5中描述了分配器的要求。

  • 由于你正在存储指针,我担心这个问题的答案会让你困惑。如果你在堆栈中分配了一个对象,并将指向该对象的指针复制到容器中,那么你的对象将仍然留在堆栈中。一旦你离开作用域,它将被销毁,你将在容器中拥有一个无效的指针。

希望能对你有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接