【问题标题】:Why doesn't automatic move work with function which return the value from rvalue reference input?为什么自动移动不适用于从右值引用输入返回值的函数?
【发布时间】:2021-12-08 14:48:57
【问题描述】:

我已经知道自动移动不能使用从 Rvalue Reference 输入返回值的函数。但为什么呢?

以下是无法使用自动移动的示例代码。

Widget makeWidget(Widget&& w) {
  ....
  return w; // Compiler copies w. not move it.
}

如果函数输入是按值复制,自动移动有效。

Widget makeWidget(Widget w) {
  ....
  return w; // Compiler moves w. not copy it.
}

【问题讨论】:

  • 移动不是复制省略。
  • @appleapple 这个例子不是 RVO 或 NRVO。但是编译器可以优化复制操作来移动操作。所以我不能称之为复制省略吗?
  • 可能重复:stackoverflow.com/a/40187776/5980430(虽然看起来 c++20 改变了规则,正如@songyuanyao 的回答所示。
  • @appleapple 感谢您的评论。但我的观点是我已经知道这种编译器行为,但为什么呢?从 c++20 接受这个右值自动移动操作意味着很多人和我有同样的想法。上述示例的移动优化似乎很简单,但为什么 c++ 在 c++20 之前不能接受这个?
  • @OP 如果不清楚,我链接到 @Yakk 的答案,其中包含一些解释。

标签: c++ copy-elision


【解决方案1】:

从 C++20 开始,代码应该可以按预期工作; returning局部变量和参数时进行自动移动操作,也适用于右值引用(C++20起)。

如果表达式是一个(可能是带括号的)id 表达式,它命名为 类型为任一变量的变量

  • 非易失性对象类型或
  • 对对象类型的非易失性右值引用(C++20 起)

LIVE

【讨论】:

  • 哇,您的意思是编译器会自动将 w 从 c++ 20 移出。但是为什么直到现在这还不是 c++ 规范呢?这似乎是非常直接的优化点。
  • @myoldgrandpa 我不确定,它可能只是 C++11 中的一个缺失,并在 C++20 中恢复。
  • 我编辑我的问题。复制省略 -> 自动移动
  • 我已经用 g++ --std=c++20 测试了上面的代码,但是自动移动不起作用。可能是编译器问题?
  • @myoldgrandpa 我用 gcc here 测试过,似乎工作正常。
【解决方案2】:

C++17标准[class.copy.elision/3]的相关部分:

在以下复制初始化上下文中,可能会使用移动操作而不是复制操作:

  • 如果return 语句中的表达式是一个(可能是带括号的)id 表达式,它使用在最内层的主体或参数声明子句中声明的自动存储持续时间来命名一个对象函数...

这不适用于:

Widget makeWidget(Widget&& w)
{
  return w;
}

因为w 没有命名具有自动存储持续时间的对象(在函数内)。

在C++20中,情况is different

隐式可移动实体是一个自动存储持续时间的变量,它可以是非易失性对象,也可以是对非易失性对象类型的右值引用。在以下复制初始化上下文中,可能会使用移动操作而不是复制操作:

  • 如果returnco_­return 语句中的表达式是命名在主体或参数声明子句中声明的隐式可移动实体 的(可能带括号的)id 表达式最里面的封闭函数...

这里,引用 w 满足这些要求,因为它是在参数声明子句中声明的右值引用。

为什么直到 C++20 才相同?我不能说;以前可能没有人提出过这样的改变。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-21
    • 2013-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多