保证复制省略是否适用于函数参数?

Does guaranteed copy elision work with function parameters?

如果我没理解错的话,从C++17开始,这段代码现在要求不进行复制:

Foo myfunc(void) {
    return Foo();
}

auto foo = myfunc(); // no copy

函数参数也是如此吗?副本会在以下代码中被优化掉吗?

Foo myfunc(Foo foo) {
    return foo;
}

auto foo = myfunc(Foo()); // will there be copies?

是也不是。引用 cppreference:

Under the following circumstances, the compilers are required to omit the copy- and move- construction of class objects [...]:

  • In initialization, if the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object

  • In a function call, if the operand of a return statement is a prvalue and the return type of the function is the same as the type of that prvalue.

因此,在您的第二个代码段中,只会调用一个默认构造函数。首先,myFunc 中的 foo 是从 Foo()(1 个默认构造)初始化的,它是纯右值。这意味着它将被省略(参见第 1 点)。

接下来,myFunc return 是 foo 的副本,不能省略,因为 foo 不是纯右值(第 2 点)。因此,迈出了一步,因为 foo 是一个缺值。但实际的 return 值是纯右值,因为它是 foo 的新实例(在 myFunc 中),并且由于第一点,它被省略了。

总之,标准保证了一次默认构造和一次移动。不能再有了。但是,编译器实际上可能会完全忽略唯一的移动。

在 C++17 中,纯右值 ("anonymous temporaries") 不再是对象。相反,它们是关于如何构造对象的说明。

他们可以根据构造指令实例化一个临时对象,但是由于没有对象 ,所以没有 copy/move 构造可以省略。

Foo myfunc(Foo foo) {
  return foo;
}

所以在这里,函数参数 foo 被移动到 myfunc 的纯右值 return 值中。您可以在概念上将其视为“myfunc return 关于如何制作 Foo 的说明”。如果您的程序 "not used" 执行了这些指令,则会自动实例化一个临时变量并使用这些指令。

auto foo = myfunc(Foo());

所以在这里,Foo() 是一个纯右值。它说 "construct a Foo using the () constructor"。然后它被用来构造 myfunc 的参数。没有省略,没有复制构造函数或移动构造函数被调用,只是 ().

myfunc.

里面发生了一些事情

myfunc return 是 Foo 类型的纯右值。这个纯右值(又名构造指令)用于构造局部变量 auto foo.

所以这里发生的是 Foo 是通过 () 构造的,然后移动到 auto foo.

据我所知,C++14 和 C++17 都不支持将函数参数省略为 return 值(我可能是错的,我没有标准的章节这里)。但是,当在 return func_arg; 上下文中使用时,它们会被隐式移动。