6

如果我理解正确,从 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?
4

2 回答 2

6

在 C++17 中,纯右值(“匿名临时对象”)不再是对象。相反,它们是关于如何构造对象的说明。

他们可以从他们的构造指令中实例化一个临时对象,但是由于那里没有对象,所以没有复制/移动构造可以省略。

Foo myfunc(Foo foo) {
  return foo;
}

所以在这里,函数参数foo被移动到 prvalue 返回值中myfunc。您可以从概念上将其视为“myfunc返回有关如何制作的说明Foo”。如果您的程序“未使用”这些指令,则会自动实例化一个临时指令并使用这些指令。

auto foo = myfunc(Foo());

所以这里Foo()是prvalue。它说“Foo使用()构造函数构造一个”。然后用它来构造 的论点myfunc。没有省略发生,没有复制构造函数或移动构造函数被调用,只是().

然后事情发生在里面myfunc

myfunc返回一个 prvalue 类型Foo。这个prvalue(又名构造指令)用于构造局部变量auto foo

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

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

于 2017-05-30T17:52:34.873 回答
1

是和不是。引用cppreference

在以下情况下,编译器需要省略类对象的复制和移动构造[...]:

  • 在初始化中,如果初始化表达式是prvalue,并且源类型的cv-unqualified版本与目标的类是同一个类,则初始化表达式用于初始化目标对象

  • 在函数调用中,如果 return 语句的操作数是纯右值,并且函数的返回类型与该纯右值的类型相同。

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

接下来,myFunc返回 的副本foo,它不能被省略,因为foo它不是纯右值(第 2 点)。因此,采取了一项措施,就像fooxvalue 一样。但是实际的返回值是一个纯右值,因为它是foo(in myFunc) 的一个新实例,并且由于第一点,它被省略了。

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

于 2017-05-29T16:22:57.280 回答