我应该让我的局部变量是常量还是可移动?

bit*_*ask 14 c++ const-correctness move-semantics c++17

我对本地范围内的任何对象的默认行为是 make it const。例如:

auto const cake = bake_cake(arguments);
Run Code Online (Sandbox Code Playgroud)

我尽量减少非功能性代码,因为这会增加可读性(并为编译器提供一些优化机会)。所以在类型系统中也反映这一点是合乎逻辑的。

然而,使用移动语义,这会产生问题:如果我cake很难或不可能复制并且我想在完成后将其传递出去怎么办?例如:

if (tastes_fine(cake)) {
  return serve_dish(cake);
}
Run Code Online (Sandbox Code Playgroud)

据我了解复制cake省略规则,不能保证副本会被删除(但我不确定这一点)。

所以,我不得不搬出cake去:

return serve_dish(std::move(cake)); // this will not work as intended
Run Code Online (Sandbox Code Playgroud)

但这std::move不会有任何用处,因为它(正确地)不会转换Cake const&Cake&&. 即使对象的生命周期已接近尾声。我们不能从我们承诺不会改变的东西中窃取资源。但这会削弱常量正确性。

那么,我怎样才能拥有我的蛋糕并吃掉它呢?

(即我怎样才能拥有常量正确性并从移动语义中受益。)

Dan*_*ica 5

我相信从一个const对象中移动是不可能的,至少使用标准的移动构造函数和非mutable成员是不可能的。但是,可以有一个const自动本地对象并为其应用复制省略(即NRVO)。在您的情况下,您可以按如下方式重写原始函数:

Cake helper(arguments)
{
   const auto cake = bake_cake(arguments);
   ...  // original code with const cake
   return cake;  // NRVO 
}
Run Code Online (Sandbox Code Playgroud)

然后,在您的原始函数中,您只需调用:

return serve_dish(helper(arguments));
Run Code Online (Sandbox Code Playgroud)

由于由 返回的对象helper已经是一个非常量值,因此可以将其移出(如果适用,可以再次省略)。

是演示此方法的现场演示。请注意,在生成的程序集中没有调用复制/移动构造函数。