C++ C++;vlaue返回复制构造函数激活
我无法找到以下问题的具体答案: 考虑以下代码:C++ C++;vlaue返回复制构造函数激活,c++,copy-constructor,return-by-value,C++,Copy Constructor,Return By Value,我无法找到以下问题的具体答案: 考虑以下代码: Obj f() { Obj o2; return o2; } int main() { Obj o1 = f(); return 0; } 在没有编译器优化的情况下,复制构造函数被激活了多少次 如果没有移动构造函数,不是一次用于将o2复制到调用函数,另一次用于构造o1吗 如果存在移动构造函数,是不是一次用于将o2复制到调用方函数,另一次用于构造o1(第二次是移动常量)?在C++17之前,有两个复制构造函数调用(即
Obj f() {
Obj o2;
return o2;
}
int main() {
Obj o1 = f();
return 0;
}
在没有编译器优化的情况下,复制构造函数被激活了多少次
如果没有移动构造函数,不是一次用于将o2复制到调用函数,另一次用于构造o1吗
如果存在移动构造函数,是不是一次用于将o2复制到调用方函数,另一次用于构造o1(第二次是移动常量)?在C++17之前,有两个复制构造函数调用(即使它们有副作用,也可以省略)。您可以通过gcc/clang中的
-fno-elide构造函数看到这一点
由于新的临时物化规则,C++17中只涉及一个副本(同样可以省略)
准确地说,它们都是移动,而不是复制。在C++17之前,是的,有两个复制构造函数调用(即使它们有副作用,也可以省略这两个调用)。您可以通过gcc/clang中的-fno-elide构造函数看到这一点
由于新的临时物化规则,C++17中只涉及一个副本(同样可以省略)
准确地说,所有这些都是移动,而不是复制。C++03及之前的版本
Obj
被复制两次。一次通过return
语句(构造返回值),一次通过复制返回值初始化o1
C++11和C++14
如果Obj
有一个可用的移动构造函数,它将移动两次,复制零次。return
语句必须使用移动,即使返回的表达式是左值。由于语言中的特殊规则,这种“移动优化”是强制性的<即使禁用优化,也不得复制代码>o2
。当初始化o1
时,会发生第二个移动
如果Obj
没有移动构造函数或隐式删除了移动构造函数,则会使用复制构造函数两次
如果Obj
有一个显式删除的移动构造函数,则由于o1
的初始化尝试使用删除的移动构造函数,因此程序的格式不正确
C++17及更高版本
如果Obj
具有可用的move构造函数,则在执行return
语句时将其移动一次。如上所述,编译器必须使用移动而不是复制。o1
的构造既不涉及复制也不涉及移动。相反,f()
中的return
语句初始化o1
,而不涉及临时变量。这是因为“保证的副本省略”:该语言要求省略副本,即使禁用了优化。这是因为f()
是一个prvalue,除非有必要,否则prvalue不会具体化(即,实例化为临时对象)。标准创建的“法律虚构”是f()
实际上返回了创建Obj
的“配方”,而不是Obj
本身。在实践中,这可以以与标准早期版本中实现的(可选)返回值优化相同的方式实现:调用方将指向o1
的指针直接传递到f
,而return
语句将Obj
构造到该指针中
如果Obj
的move构造函数被隐式删除或不存在,则return
语句将使用copy构造函数,因此将有一个copy和零个move
如果显式删除了Obj
的move构造函数,则程序的格式与C++11/C++14的情况相同
无论如何
可以优化上述情况下的复制/移动。在涉及多个复制/移动操作的情况下,编译器可以优化其中任何一个或所有操作。C++03及之前的版本
Obj
被复制两次。一次通过return
语句(构造返回值),一次通过复制返回值初始化o1
C++11和C++14
如果Obj
有一个可用的移动构造函数,它将移动两次,复制零次。return
语句必须使用移动,即使返回的表达式是左值。由于语言中的特殊规则,这种“移动优化”是强制性的<即使禁用优化,也不得复制代码>o2。当初始化o1
时,会发生第二个移动
如果Obj
没有移动构造函数或隐式删除了移动构造函数,则会使用复制构造函数两次
如果Obj
有一个显式删除的移动构造函数,则由于o1
的初始化尝试使用删除的移动构造函数,因此程序的格式不正确
C++17及更高版本
如果Obj
具有可用的move构造函数,则在执行return
语句时将其移动一次。如上所述,编译器必须使用移动而不是复制。o1
的构造既不涉及复制也不涉及移动。相反,f()
中的return
语句初始化o1
,而不涉及临时变量。这是因为“保证的副本省略”:该语言要求省略副本,即使禁用了优化。这是因为f()
是一个prvalue,除非有必要,否则prvalue不会具体化(即,实例化为临时对象)。标准创建的“法律虚构”是f()
实际上返回了创建Obj
的“配方”,而不是Obj
本身。在实践中,这可以通过与(可选)返回值optimiza相同的方式实现