假设我有这个函数:
template <class A>
inline A f()
{
A const r(/* a very complex and expensive construction */);
return r;
}
既然const
变量不能移动,那么声明r
const
是个好主意吗?请注意,返回的值不是const
。我感到不安的是,r
确实是const
,但这样声明可能不是一个好主意。然而,限定符应该帮助编译器生成更好的代码。
如这里所示,NRVO消除了return r;
行所隐含的r
的副本
#include <iostream>
struct A {
const char* name;
A( const char* name_ ):name(name_) { std::cout << "created " << name << "n"; }
A(A const&){ std::cout << "copied " << name << "n"; }
A(A &&){ std::cout << "moved " << name << "n"; }
};
A f() {
std::cout << "start of f()n";
A const r("bob");
std::cout << "body of f()n";
return r;
}
int main() {
A x = f();
}
并且main
中的副本也被消除。
如果您以其他方式阻止NRVO和RVO(例如,在使用GCC编译时使用标志-fno-elide-constructors
),const
可能会导致复制您的对象,而不是move
d。如果我们从A
:中删除复制构造函数,您可以看到这一点
#include <iostream>
struct A {
const char* name;
A( const char* name_ ):name(name_) { std::cout << "created " << name << "n"; }
//A(A const&){ std::cout << "copied " << name << "n"; }
A(A &&){ std::cout << "moved " << name << "n"; }
};
A f() {
std::cout << "start of f()n";
A const r("bob");
std::cout << "body of f()n";
return r;
}
int main() {
A x = f();
}
代码不再编译。虽然只要出现NRVO,复制构造函数就不会执行,但const
局部变量需要它的存在。
现在,NRVO需要一些东西,比如一个沿着所讨论函数的每个执行路径返回的单个变量:如果你"中止"并执行return A()
,NRVO就会被阻止,而你的const
本地变量会突然在所有返回位置强制复制。
如果class A
在您的控制之下,并且您希望通过移动返回const
对象,则可以执行
mutable bool resources_were_stolen = false;
并在CCD_ 19移动构造函数中将其设置为true
A(const A&& other) { ...; other.resources_were_stolen = true; }
~A() { if (!resources_were_stolen) ... }
事实上,析构函数可能会变成if (resources_were_stolen) some_unique_ptr.release();
,因为对象在构造和销毁过程中会失去const
的性质。