如果我理解正确,从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?
答案 0 :(得分:5)
在C ++ 17中,prvalues(" anonymous temporaries")不再是对象。相反,它们是关于如何构造对象的说明。
他们可以从他们的构造指令中实例化一个临时表,但是因为没有对象那里,所以没有复制/移动构造来消除。
Foo myfunc(Foo foo) {
return foo;
}
所以在这里,函数参数foo
被移动到prvalue返回值myfunc
。您可以在概念上将其视为" myfunc
返回有关如何制作Foo
"的说明。如果这些说明是"未使用"通过您的程序,临时自动实例化并使用这些指令。
auto foo = myfunc(Foo());
所以在这里,Foo()
是一个prvalue。它说"使用Foo
构造函数"构造()
。然后用它来构造myfunc
的参数。不会出现任何省略,也不会调用复制构造函数或移动构造函数,只需()
。
东西发生在myfunc
内。
myfunc
返回Foo
类型的prvalue。这个prvalue(又名构造指令)用于构造局部变量auto foo
。
所以这里发生的是Foo
是通过()
构建的,然后移入auto foo
。
据我所知,在C ++ 14和C ++ 17中不支持将函数参数省略为返回值(我可能错了,我这里没有标准的章节和章节)。但是,在return func_arg;
上下文中使用它们时会隐式移动它们。
答案 1 :(得分:1)
是和否。引用cppreference:
在下列情况下,编制者需要省略类对象的复制和移动构造[...]:
在初始化中,如果初始化表达式是prvalue且源类型的cv-nonqualified版本与目标类相同,则初始化表达式用于初始化目标对象
在函数调用中,如果return语句的操作数是prvalue,并且函数的返回类型与该prvalue的类型相同。
因此,在您的第二个片段中,只会调用一个默认构造函数。首先,foo
中的myFunc
是从Foo()
(1默认构造)初始化的,这是一个prvalue。这意味着它将被省略(见第1点)。
接下来,myFunc
会返回foo
的副本,由于foo
不是prvalue(第2点),因此无法将其删除。因此,进行了一次移动,因为foo
是xvalue。但是实际的返回值是一个prvalue,因为它是foo
的新实例(在myFunc
中),并且因为第一点它被省略了。
总之,标准保证一个默认构造和一个移动。不能再有了。但是,编译器实际上可能完全忽略了唯一的移动。