【问题标题】:Does (N)RVO also happen when the value is being copied into an existent object?当值被复制到现有对象时,(N)RVO 是否也会发生?
【发布时间】:2015-10-25 22:07:37
【问题描述】:

(N)RVO 有助于在将返回值分配给新变量时避免不必要的复制和创建临时对象(从而避免复制构造函数)。

所以这样的事情应该由 RVO 优化:

MyObj getMyObj() {
  return MyObj();
}

MyObj myobj = getMyObj();

但是,调用站点对象已经存在时也会发生这种情况吗? (即在使用 = 运算符而不是复制构造函数的情况下)。我试图找到有关此的文献,但 (N)RVO 似乎总是以避免复制构造函数来描述。不确定在这种情况下修改调用站点对象是否真的安全。

MyObj myobj;

//will getMyObj() first create a temporary object and then copy it via the = operator?
myobj = getMyObj();

【问题讨论】:

  • 抛开标准不谈,如果不调用分配operator,第二个示例怎么可能工作? (我假设您的程序可以观察到创建和赋值之间的myobj 状态。)编译器可以首先运行析构函数,然后就地构造一个new 对象。但是,这怎么会比使用分配operator 更有效呢? (正如 Steve Jessop 所解释的那样,它也不是异常安全的。)
  • @5gon12eder 由于您提到的原因,我很确定它不会这样做。但是我不确定在底层是否有其他一些神奇的机制可以检测到函数不能中途停止(它不会抛出)并通过引用隐式传递调用站点变量,以便函数直接更新它。

标签: c++ rvo nrvo


【解决方案1】:

不,RVO 不适用。 (N)RVO 在标准中仅定义为构造函数省略。

动机是如果MyObj()的构造函数抛出,那么在第二个代码sn -p myobj已经存在,并且应该继续存在于调用getMyObj()之前的状态。

除此之外,我认为一般情况下如何实际实现就地施工并不清楚。 myobj 是一个已经构造好的对象,只有 operator=“知道”如何用不同的资源替换它所拥有的任何资源。

getMyObj 的返回值仍然可以直接构造,并且调用代码可以从operator=(MyObj &&)(移动赋值)中受益(如果有的话)。因此,代码不一定需要复制构造或复制赋值,但它确实需要一个不能省略的赋值。

如果所有内容都是内联的,并且MyObj() 不能抛出,并且赋值没有副作用,那么编译器可能会应用“as-if”规则,并且不管具体规则如何进行优化(N)RVO!

【讨论】:

  • 感谢您的澄清。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-27
  • 1970-01-01
  • 2022-06-27
相关资源
最近更新 更多