const value and RVO



假设我有这个函数:

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可能会导致复制您的对象,而不是moved。如果我们从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的性质。

最新更新