C++标准允许实现合并分配内存吗?

6
我正在观看Jonathan Blow的视频关于一种新的游戏编程语言的想法,其中他讨论了游戏编程中的常见模式,称之为“联合分配”。这个想法是当你有一个类有几个成员是动态分配数组(可以是std::vector但由于它们是固定大小,更像是建议的std::dynarray),你预先分配足够存储所有数组数据的内存,并执行仅足够所有数组的一个大分配,而不是每个数组都进行一次分配。

他提出直接语言支持这种模式,这让我想知道C++标准是否允许实现以这种方式合并分配?我认为这需要编译器付出一些英勇的努力来实际实现优化,但我没有看到明显的理由为什么原则上不能这样做。有人知道这在标准下不被允许吗,甚至是否已经有实现在实践中执行此优化?


这对于动态分配的数组来说怎么可能实现呢?例如,如果您尝试向向量中添加比包含对象中分配的空间更多的元素会发生什么? - cdhowie
是的,您可以使用自定义分配器来获得这样的行为。我在这里有一个例子:http://ideone.com/umU1UC。我想知道的是规范是否允许实现执行此优化。 - mattnewport
@mattnewport 对,没错,这将是这种优化的非常好的候选者...假设程序员不会将一个dynarray分配给另一个,或者做任何傻事,比如给一个类成员std::dynarray<int> m_dynarray;m_dynarray.~dynarray(); new (&m_dynarray) std::dynarray<int>(100000);,我IRC展示了定义行为。这里有很多复杂的陷阱。 - cdhowie
@cdhowie 当然,毫无疑问它将是一个英雄般的优化器 :) 如果优化器具有相关代码的全局可见性,那么似乎是可能的。 - mattnewport
@mattnewport 没错,同意。如果程序员做了一些欺骗优化器的未定义行为,那么就是未定义行为。 :) - cdhowie
显示剩余5条评论
1个回答

11

是的,标准允许合并内存分配(C++14):

5.3.4 New [expr.new]

10 当实现这样做时,可以省略对可替换全局分配函数(18.6.1.1,18.6.1.2)的调用。此时,将由实现提供存储,或通过扩展另一个 new-expression 的分配提供存储。如果不扩展分配,则实现可能会扩展 new-expression e1 的分配以为 new-expression e2 提供存储,如果以下内容在未扩展分配时为真,则可以这样做:

  • e1的评估在e2的评估之前进行,并且
  • 每当e1获得存储时,都会计算e2,并且
  • 两个e1e2都调用相同的可替换全局分配函数,并且
  • 如果由e1e2调用的分配函数抛出异常,则在评估任一e1e2中引发的任何异常都将首先在同一处理程序中捕获,并且
  • e1e2生成的指针值是计算的 delete-expression 的操作数,并且
  • e2的评估在以e1生成的指针值为操作数的 delete-expression 的评估之前进行。

C++11不允许合并或省略此类内存分配。


谢谢,这正是我在寻找的信息! - mattnewport
@Casey 这是 C++14 的新语言吗? - mattnewport
2
@mattnewport 是的。请参见N3664,该文件于2013年5月被采纳为C++14工作文件(根据编辑报告N3692)。 - Casey
2
需要注意的是,这仅涉及可替换的全局分配函数。如果编译器可以检测到 new 和其它相关函数没有被替换,则根据 as-if 规则允许进行任何操作。 - n. m.
@n.m.:嗯,如果没有可观察到的差异,当然编译器可以随心所欲地做任何事情。不过这并不是什么新鲜事,as-if规则必须始终被考虑到。 - Deduplicator

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