如果我理解正确,从 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?
如果我理解正确,从 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?
在 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;
上下文中使用时会隐式移动。
是和不是。引用cppreference:
在以下情况下,编译器需要省略类对象的复制和移动构造[...]:
在初始化中,如果初始化表达式是prvalue,并且源类型的cv-unqualified版本与目标的类是同一个类,则初始化表达式用于初始化目标对象
在函数调用中,如果 return 语句的操作数是纯右值,并且函数的返回类型与该纯右值的类型相同。
因此,在您的第二个片段中,只会调用一个默认构造函数。首先,foo
in是从(1 个默认构造)myFunc
初始化的,它是一个纯右值。Foo()
这意味着它将被忽略(见第 1 点)。
接下来,myFunc
返回 的副本foo
,它不能被省略,因为foo
它不是纯右值(第 2 点)。因此,采取了一项措施,就像foo
xvalue 一样。但是实际的返回值是一个纯右值,因为它是foo
(in myFunc
) 的一个新实例,并且由于第一点,它被省略了。
总之,标准保证了一种默认构造和一种移动。不能再有了。但是,编译器实际上可能完全忽略了唯一的动作。