将参数省略复制为 return 值

Copy elision of arguments as return values

  1. 鉴于以下情况; C++17 会保证复制省略吗?
template <typename Widget>
Widget frobnicate(Widget w) {
  // optionally mutate w in some way
  return w;
}
  1. 如果 Widget 实现移动构造函数,答案会改变吗?

  2. 我应该 return 搬家吗?例如,在这种情况下:

return std::move(w);
  1. 没有。我们不能保证从函数参数中复制省略。如果您从实现的角度考虑这一点 - 您的参数 w 必须存在于某个寄存器或地址中,因此它不能首先构造到 return 槽中。

  2. 鉴于 (1),有点无意义。

  3. 你永远不应该†‡return std::move(w);因为这实际上会抑制在快乐情况下的复制省略:

    Widget frobnicate() {
        Widget w;
        return std::move(w); // oops
    }
    

除了在 C++17 中实际上有一些不幸的地方你实际上需要写 std::move 因为有些地方对象不会自动为你搬离。有关几个示例,请参阅 P0527 and P1155(OP 案例 - returning 一个函数参数 - 不是其中之一;甚至在 C++17 中也会隐式移动该案例)。 C++20 也会隐含地从所有这些情况中转移,所以你真的不应该return std::move(w);

当然可以,除非w不是一个函数参数或局部变量自动存储时间。然后语言中没有任何内容可以安全地假定它可以代表您移动它,因此您必须明确地这样做。

复制省略只会发生在方法中实例化的变量上。 Thar是由于如何复制省略。调用者在调用被调用者时会将 space 设为 return 值。但是为了使用那个 space,被调用者必须在它的定义中使用这个 space 创建一个变量(理论上它可能可以直接在参数中制作的副本(因为它是由值)到这个 space vut 编译器还不是那么好)) 资料来源:关于复制省略的 cppcon 讨论。

移动构造函数的存在不会给你复制省略,但如果复制省略是不可能的,编译器将首先尝试移动,如果不可能移动,然后再复制。所以如果没有复制省略,移动构造函数的存在可能会提高速度。

你永远不应该 return std::move 临时变量(即在函数末尾超出范围的变量),因为它可以防止复制省略,即使复制省略是不可能的,编译器将默认移动。 mkve return 的唯一原因(我能想到)是,如果您要释放调用前对象持有的资源。例如 std::unique_ptr::release 应该 return by move, iirc.