【问题标题】:Is returning with `std::move` sensible in the case of multiple return statements?在多个返回语句的情况下,使用 `std::move` 返回是否明智?
【发布时间】:2012-03-20 21:58:29
【问题描述】:

我知道返回std::move 通常不是一个好主意,即

bigObject foo() { bigObject result; /*...*/ return std::move(result); }

而不是简单

bigObject foo() { bigObject result; /*...*/ return result; }

因为它妨碍了返回值优化。但是对于具有多个不同返回的函数,特别是像

class bar {
  bigObject fixed_ret;
  bool use_fixed_ret;
  void prepare_object(bigObject&);
 public:
  bigObject foo() {
    if(use_fixed_ret)
      return fixed_ret;
     else{
      bigObject result;
      prepare_object(result);
      return result;
    }
  }
};

我认为在这样的函数中不可能进行正常的返回值优化,所以放入是个好主意

      return std::move(result);

在这里,或者我应该这样做(IMO 更丑,但这值得商榷)

  bigObject foo() {
    bigObject result;
    if(use_fixed_ret)
      result = fixed_ret;
     else{
      prepare_object(result);
    }
    return result;
  }

【问题讨论】:

  • 我无法参考标准,所以我不会做出答案,但我确信你不需要 std::move,我认为你混淆了 RVO 和复制省略,复制省略是有利于某些具有单个返回路径的编译器的优化。 BigObject 将成为其返回位置的 R 值。
  • 是的,我认为复制省略是我一开始的意思。
  • 另外,如果你喜欢干净的代码和代码级别的优化,你似乎喜欢,:),你可以在你的 foo() 函数中去掉 else{... 分支。好像第一个语句为真,那么第二个语句不会被评估。
  • 在您的示例中,您正在移动成员变量fixed_ret。所以多次调用该函数可能不起作用。
  • @balki "移动你的成员变量fixed_ret" 是吗?怎么样?

标签: c++ c++11 move-semantics return-value-optimization


【解决方案1】:

对于局部变量,大多数时候不需要在return 语句中使用std::move 它们,因为语言实际上要求这种情况自动发生:

§12.8 [class.copy] p32

当满足或将满足删除复制操作的条件时,除了源对象是函数参数这一事实之外,并且要复制的对象由左值指定,重载决议选择复制的构造函数首先执行,就好像对象是由右值指定的一样。如果重载决议失败,或者如果所选构造函数的第一个参数的类型不是对对象类型的右值引用(可能是 cv 限定的),则再次执行重载决议,将对象视为左值。 [ 注意: 无论是否会发生复制省略,都必须执行此两阶段重载解决方案。它确定如果不执行省略则要调用的构造函数,并且即使调用被省略,所选构造函数也必须是可访问的。 ——尾注 ]


† 复制省略的应用范围非常有限 (§12.8/31)。一个这样的限制是,在处理返回语句时,源对象的类型必须与函数的 cv 非限定返回类型相同。它也不适用于即将超出范围的局部变量的子对象。

【讨论】:

  • 这是您的标准参考。
  • 好吧...我总是对标准中的表述有困难,现在读了五遍,仍然不太明白它应该是什么意思。但是你说,在我的例子中,它只是意味着“第一个版本就这么好”?那我就相信你了。
  • @leftaroundabout:它基本上说“如果对象是本地的,并且是按值返回的,首先尝试将它作为右值返回(就像std::move 那样)。如果没有找到移动 ctor,尝试相同,但这次作为左值。
  • @Xeo 我可以简化一下,如果不是,请先尝试移动构造函数,使用复制构造函数?
猜你喜欢
  • 2018-03-21
  • 2013-04-05
  • 1970-01-01
  • 1970-01-01
  • 2017-10-26
  • 2013-05-29
  • 2017-10-19
  • 1970-01-01
相关资源
最近更新 更多