This question处于不同的方面(也限于gcc)。我的问题仅适用于未命名对象。允许Return Value Optimization 更改生成的程序的可观察行为 。这似乎也在标准中提到。
然而,这个"允许" 术语令人困惑。这是否意味着每个编译器都会发生RVO 保证。由于RVO下面的代码改变了它的可观察行为:
#include<iostream>
int global = 0;
struct A {
A(int *p) {}
A(const A &obj) { ++ global; }
};
A foo () { return A(0); } // <--- RVO happens
int main () {
A obj = foo();
std::cout<<"global = "<<global<<"\n"; // prints 0 instead of 2
}
该程序是否假设为所有实现打印global = 0
,而不管编译器优化和方法大小为foo
?
答案 0 :(得分:4)
根据标准,程序可以打印0,1或2.C ++ 11中的特定段落是12.8p31,以:
开头当满足某些条件时,允许实现省略类对象的复制/移动构造,即使该对象的复制/移动构造函数和/或析构函数具有副作用。
请注意,两个副本元素都不属于 as-if 规则中的优化(这要求程序的行为与同一程序的行为一致 as-如果没有进行任何优化)。该标准明确允许实现生成不同的可观察行为,程序员可以让您的程序不依赖于该程序(或接受所有三种可能的结果)。
注2:在任何答案中都没有提到1,但这是可能的结果。有两个可能的副本,从函数中的局部变量到返回的对象到main
中的对象,编译器可以忽略所有,一个或两个副本生成所有三个可能的输出。
答案 1 :(得分:2)
迂腐地说明其实施的定义。现代编译器足够聪明,可以进行这种优化。
但是不能保证这些行为在实现中完全相同。这就是实现定义行为的全部内容。
“允许”在此上下文中表示0
或1
或2
是符合标准的输出。
答案 2 :(得分:2)
无法保证。如果你试图连贯地写出这样的保证,你就会发现不可能这样做。
例如,请考虑以下代码:
std::string f() {
std::string first("first");
std::string second("second");
return FunctionThatIsAlwaysFalse() ? first : second;
}
函数FunctionThatIsAlwaysFalse
始终返回false
,但您只能告诉您是否进行模块间优化。标准是否要求每个编译器进行模块间优化,以便在这种情况下可以使用RVO?那会怎么样?或者,当需要进行模块间优化时,是否应该禁止任何编译器使用RVO?那会怎么样?怎么能阻止那些足够聪明的编译器看到RVO可以做到这一点而那些不是没有做过的?
标准列表是否需要每个优化编译器都支持RVO?在其他情况下是否应该禁止RVO?那会不会失败优化编译器的重点?
那么编译器认为RVO会降低性能的情况又如何呢?是否应该要求编译器进行优化,它认为是坏的?例如:
if(FunctionCompilerKnowsHasNoSideEffectsAndThinksMostlyReturnsFalse())
return F(3); // Here RVO is a pessimization
else
{
Foo j=F(3);
return Foo(j);
}
这里,如果编译器不需要执行RTO,如果可以避免if
和函数调用,因为没有RTO,代码在两半中都是相同的。你是否应该强制编译器进行优化,它认为会让事情变得更糟?为什么呢?
真的没办法做出这样的保证工作。