保证复制省略是否适用于函数参数?
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;
上下文中使用时,它们会被隐式移动。
如果我没理解错的话,从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;
上下文中使用时,它们会被隐式移动。