请考虑以下代码。调用doStuff()但未使用返回值时会发生什么? SomeClass还在创建吗?当然,创建本身可能会产生重要的副作用,但复制构造函数也是如此,它们在RVO / copy-elision中仍然被省略。
SomeClass doStuff(){
//...do stuff
return SomeClass( /**/);
}
SomeClass some_object = doStuff();
doStuff(); //What happens here?
(编辑:用GCC -O3对此进行测试。对象构建然后立即被破坏)
答案 0 :(得分:22)
对于RVO和复制省,我觉得有一个误解。这并不意味着不创建函数的返回值。它始终是创建的,这不是实现可以做的事情。
唯一的余地是,尽管存在副作用,但是在复制副本时,还是要削减中间人。使用调用结果初始化对象时,标准允许插入目标对象,以便函数直接初始化。
如果您没有提供目标对象(通过使用结果),则必须实现并销毁临时对象,作为包含函数调用的完整表达式的一部分。
所以要举一点你的例子:
doStuff(); // An object is created and destroyed as part of temporary materialization
// Depending on the compilers analysis under the as-if rule, there may be
// further optimization which gets rid of it all. But there is an object there
// formally.
std::rand() && (doStuff(), std::rand());
// Depending on the result of std::rand(), this may or may not create an object.
// If the left sub-expression evaluates to a falsy value, no result object is materialized.
// Otherwise, one is materialized before the second call to std::rand() and
// destroyed after it.
答案 1 :(得分:6)
编译者可能会在某些情况下忽略不必要的副本,即使它有副作用,是的。
编译器可能不忽略对象的整个存在,如果它有副作用。
如果没有副作用,则无法观察到结果,因此是否存在是否存在实际上是一个无问题。
tl; dr:该标准列出了非常具体的省略机会,而这不是其中之一。