Yan*_* K. 2 c++ copy-constructor return-by-value
我无法找到以下问题的具体答案:
考虑以下代码:
Obj f() {
Obj o2;
return o2;
}
int main() {
Obj o1 = f();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在没有编译器优化的情况下,复制构造函数被激活了多少次?
如果没有移动构造函数,不是一次将o2复制到调用函数,另一次构造o1吗?
如果有move构造函数,不是一次将 o2 复制到调用函数,另一次构造 o1 (第二次是 move const)?
Obj被复制两次。一次通过return语句(构造返回值),一次o1通过复制返回值来初始化。
如果Obj有可用的移动构造函数,则会移动两次并复制零次。return即使返回的表达式是左值,该语句也必须使用移动。由于语言中的特殊规则,这种“移动优化”是强制性的;o2即使禁用优化,也不得复制。o1初始化时会发生第二次移动。
如果Obj没有移动构造函数或隐式删除的移动构造函数,则复制构造函数将使用两次。
如果Obj有显式删除的移动构造函数,则程序格式错误,因为 的初始化o1尝试使用已删除的移动构造函数。
如果Obj有可用的移动构造函数,则在return执行语句时将其移动一次。如上所述,编译器必须使用移动而不是复制。的构建o1既不涉及复制也不涉及移动。相反,initializereturn中的语句不涉及临时变量。这是因为“保证复制省略”:即使禁用优化,该语言也要求删除副本。这是因为是一个纯右值,除非有必要,否则不会具体化纯右值(即实例化为临时对象)。该标准创建的“法律虚构”实际上返回的是创建的“配方” ,而不是其本身。实际上,这可以与标准早期版本中实现(可选)返回值优化相同的方式实现:调用者将指针直接传递到,并且语句构造到该指针中。f()o1f()f()ObjObjo1freturnObj
如果 的移动构造函数Obj被隐式删除或不存在,则该语句将使用复制构造函数return,因此将出现一份复制和零次移动。
如果显式删除 的移动构造函数Obj,则程序的格式不正确,如 C++11/C++14 情况一样。
上述情况下的复制/移动都可以优化掉。在涉及多个复制/移动操作的情况下,编译器可以优化其中任何一个或全部操作。