【问题标题】:Return Value Optimization: Explicit move or implicit?返回值优化:显式移动还是隐式移动?
【发布时间】:2020-06-06 10:43:33
【问题描述】:

我有这样的功能,我必须在这里显式使用 move 还是隐式使用?

std::vector<int> makeVector();
std::vector<int> makeVector2();

std::optional<std::vector<int>> getVectOr(int i) {
  if(i==1) {
    std::vector<int> v = makeVector();
    return std::move(v);
  }
  else if(i==2) {
    std::vector<int> v2 = makeVector2();
    return std::move(v2);
  }
  return std::nullopt;
}

【问题讨论】:

    标签: c++ c++17 rvo


    【解决方案1】:

    不管你是否使用std::move。这里不会进行返回值优化。进行 RVO 有几个要求。

    返回值优化的要求之一是返回的值必须与函数返回的值同一类型

    std::optional<std::vector<int>> getVectOr(int i)
    

    您的函数返回std::optional&lt;std::vector&lt;int&gt;&gt;,因此只有相同类型的临时副本会被省略。在此处讨论的两个 return 语句中,两个临时变量都是 std::vector&lt;int&gt;s,当然它们的类型不同,因此不会发生 RVO。

    无论发生什么,您都会返回std::optional&lt;std::vector&lt;int&gt;&gt;。这是这里的绝对要求。没有例外。但是你从这个函数返回一些东西的冒险总是从std::vector&lt;int&gt;开始。不管你怎么尝试,你都无法把它变成完全不同的类型。在此过程中,必须在某个地方建造一些东西。无返回值优化。

    但话虽如此:这里也有移动语义。如果星星幸运地为您对齐(这很可能),则移动语义将允许一切发生,而无需复制大向量的内容。因此,尽管没有进行返回值优化,但您可能会中奖并让一切顺利进行,而无需在所有 RAM 中重新排列向量的实际内容。您可以自己使用调试器来确认或否认您是否在该帐户中中了彩票。

    您也可能使用其他类型的 RVO,即 return从函数中获取非易失性自动作用域对象:

    std::optional<std::vector<int>> getVectOr(int i) {
    
        std::optional<std::vector<int>> ret;
    
        // Some code
    
        return ret;
     }
    

    也可以在这里进行返回值优化,这是可选的,但不是强制性的。

    【讨论】:

    • 更新了我的答案,我最初写的时候错误地想到了另一种情况。
    【解决方案2】:

    除了已经说过的:

    在返回语句中使用std::move禁止返回值优化。仅当 return 语句的操作数是在函数体中声明的自动非易失性存储变量的名称并且其类型等于(直到 cv 限定)返回类型时,才允许命名返回值优化。

    std::move(v2) 不符合此条件。它不是简单地命名一个变量。

    命名返回值优化也不是强制性的。它是可选的,取决于编译器是否会执行它(即使在 C++17 中强制进行一些复制省略)。

    但是,如果不做返回值优化,那么一般返回值会自动移动。 return 语句具有特殊行为,如果操作数直接命名具有与上述类似条件的变量,则将执行重载决议,就好像返回值初始化程序是一个右值表达式(即使它不是),所以移动构造函数会被考虑。无论return 语句中引用的变量类型是否与返回类型相同,都会自动执行此移动,因此它也适用于您的示例。

    没有必要明确使用std::move,如上所述,在某些情况下(尽管不是你的具体情况)这是一种悲观。所以只需使用:

    std::optional<std::vector<int>> getVectOr(int i) {
      if(i==1) {
        std::vector<int> v = makeVector();
        return v;
      }
      else if(i==2) {
        std::vector<int> v2 = makeVector2();
        return v2;
      }
      return std::nullopt;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-01
      • 2020-09-07
      • 2017-10-14
      • 2016-04-13
      • 1970-01-01
      相关资源
      最近更新 更多