说我有这个功能:
template <class A>
inline A f()
{
A const r(/* a very complex and expensive construction */);
return r;
}
r
const
由于const
无法移动变量,因此声明是个好主意吗?请注意,返回值不是const
. 我正在努力解决的问题是,r
确实如此const
,但将其声明为这样可能不是一个好主意。然而,限定符应该有助于编译器生成更好的代码。
如此处所示,NRVO 省略r
了该行所隐含的副本return 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(例如-fno-elide-constructors
在使用 GCC 编译时使用标志),则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 需要一些东西,例如沿相关函数的每个执行路径返回的单个变量:如果您曾经“中止”并执行 a return A()
,则 NRVO 被阻塞,并且您的const
局部变量突然强制复制所有返回站点。
如果class A
在您的控制之下,并且您想通过移动返回const
对象,您可以这样做
mutable bool resources_were_stolen = false;
const
并在移动构造函数中将其设置为 true
A(const A&& other) { ...; other.resources_were_stolen = true; }
~A() { if (!resources_were_stolen) ... }
实际上,析构函数可能会变成if (resources_were_stolen) some_unique_ptr.release();
,使用对象const
在构造和销毁过程中失去它们的特性。