从函数返回的对象是否在未使用时仍然创建?

Ady*_*Ady 19 c++ lifetime

请考虑以下代码.调用doStuff()但未使用返回值时会发生什么?SomeClass还在创建吗?当然,创建本身可能会产生重要的副作用,但复制构造函数也是如此,它们在RVO/copy-elision中仍然被省略.

SomeClass doStuff(){
    //...do stuff
    return SomeClass( /**/);
}

SomeClass some_object = doStuff();
doStuff(); //What happens here?
Run Code Online (Sandbox Code Playgroud)

(编辑:用GCC -O3对此进行测试.构造对象然后立即销毁)

Sto*_*ica 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.
Run Code Online (Sandbox Code Playgroud)

  • @Yola - 如果没有可观察到的行为受到影响,那肯定会.取决于正在创建的对象.但这不是关于复制省略,而是关于在as-if规则下的优化.从抽象C++机器的角度来看,那里有一个对象. (9认同)
  • @Caninonos - 这是一个非常常见的优化,如果它想要相关的话,编译器可以更好地实现它.[但标准只说实施*允许*](https://timsong-cpp.github.io/cppwp/n4659/class.copy.elision#1),没有义务.值得注意的是,RVO是一种不同的优化形式,与C++ 17规定的保证副本省略没有直接关系. (4认同)
  • @Dai:记住,C++源代码_描述了一个program_.它不是在计算机上执行的一系列指令.这就是编译程序集的用途.人们有时将其称为"优化",但它实际上只是语言_is_的基本性质.确实,您的编译器可以根据"优化级别"设置生成更高效或更低效(和模糊处理)的代码,但这与C++是您希望计算机执行的_abstract表示无关. (4认同)
  • 你说"标准允许插入目标对象"(强调"允许").是真的"允许"还是"需要"?或根据具体情况允许/要求? (2认同)
  • @StoryTeller:没问题.我拿PayPal;) (2认同)

Lig*_*ica 6

在某些情况下,编译器可能会删除不必要的副本,即使它有副作用,是的.

如果对象具有副作用,编译器可能不会忽略对象的整个存在.

如果它没有副作用,那么就没有可观察到的结果,因此存在是否发生实际上是一个非问题.

tl;博士:标准列出了非常具体的省略机会,而这不是其中之一.