Cor*_*mer 63 c++ memory-management compiler-optimization language-lawyer
就编译器优化而言,将堆分配更改为堆栈分配是否合法和/或可能?或者会破坏as-if规则?
例如,假设这是代码的原始版本
{
Foo* f = new Foo();
f->do_something();
delete f;
}
Run Code Online (Sandbox Code Playgroud)
编译器是否能够将此更改为以下内容
{
Foo f{};
f.do_something();
}
Run Code Online (Sandbox Code Playgroud)
我不这么认为,因为如果原始版本依赖于自定义分配器之类的东西,那将会产生影响.标准是否对此有具体说明?
gez*_*eza 51
是的,这是合法的.expr.new/10C++ 14:
允许实现省略对可替换全局分配函数的调用(18.6.1.1,18.6.1.2).当它这样做时,存储由实现提供,或者通过扩展另一个新表达式的分配来提供.
expr.delete/7:
如果delete-expression的操作数的值不是空指针值,则:
- 如果没有省略要删除的对象的new-expression的分配调用并且未扩展分配(5.3.4),则delete-expression应调用释放函数(3.7.4.2).从new-expression的分配调用返回的值应作为第一个参数传递给deallocation函数.
- 否则,如果扩展分配或通过扩展另一个新表达式的分配来提供分配,并且已经评估了由具有由扩展的new-expression提供的存储的new-expression产生的每个其他指针值的delete-expression ,delete-expression应调用deallocation函数.从扩展new-expression的分配调用返回的值应作为第一个参数传递给deallocation函数.
- 否则,delete-expression不会调用释放函数(3.7.4.2).
因此,总而言之,替换new和delete定义某些实现是合法的,比如使用堆栈而不是堆.
注意:正如Massimiliano Janes评论的那样,编译器无法完全坚持您的示例的转换,如果do_something抛出:f在这种情况下编译器应该省略析构函数调用(在这种情况下,您的转换后的示例会调用析构函数).但除此之外,它可以自由地放入f堆栈.
这些并不等同.f.do_something()可能会抛出,在这种情况下,第一个对象保留在内存中,第二个对象被破坏.