[C++11: 12.8/31] 中有说明:
这种复制/移动操作的省略(称为复制省略)是允许的 [...] :
— 在具有类返回类型的函数的 return 语句中,当表达式是非易失性自动对象的名称时 (除了函数或 catch 子句参数之外) 与函数返回类型具有相同的 cv-unqualified 类型,可以通过直接将自动对象构造到函数的返回值中来省略复制/移动操作
这意味着
#include <iostream>
using namespace std;
struct X
{
X() { }
X(const X& other) { cout << "X(const X& other)" << endl; }
};
X no_rvo(X x) {
cout << "no_rvo" << endl;
return x;
}
int main() {
X x_orig;
X x_copy = no_rvo(x_orig);
return 0;
}
将打印
X(const X& other)
no_rvo
X(const X& other)
为什么需要第二个复制构造函数?编译器不能简单地延长生命周期吗x?
Imagine no_rvo
是在不同的文件中定义的main
这样编译时main
编译器只会看到声明
X no_rvo(X x);
并且不知道该类型的对象是否X
已返回any与论证的关系。据当时所知,实施no_rvo
也可以是
X no_rvo(X x) { X other; return other; }
所以当它例如编译该行
X const& x = no_rvo(X());
当最大限度地优化时,它将执行以下操作。
- 生成要传递给的临时 X
no_rvo
作为论据
- call
no_rvo
,并将其返回值绑定到x
-
destruct它传递给的临时对象
no_rvo
.
现在如果返回值来自no_rvo
与传递给它的对象是同一个对象,那么临时对象的销毁将意味着返回对象的销毁。但这是错误的,因为返回的对象绑定到一个引用,因此将其生命周期延长到该语句之外。然而,仅仅不破坏论证也不是解决方案,因为如果定义no_rvo
是我上面展示的替代实现。因此,如果允许函数重用参数作为返回值,则可能会出现编译器无法确定正确行为的情况。
请注意,对于常见的实现,编译器无论如何都无法对其进行优化,因此,正式允许这样做并不是一个很大的损失。另请注意,编译器is如果可以证明这不会导致可观察行为的变化(所谓的假设规则),则无论如何都可以优化副本。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)