我正在阅读Prata的C ++书籍,在谈论复制构造函数时,它表示在以下情况下调用此构造函数:
假设我们正在使用Vector
类。
为了理解sakes,在本章的示例中,我们在构造函数/析构函数定义中包含了字符串输出,以指示调用它们的时间和时间。
例如,如果我们有
int main()
{
Vector v1; // print "Default constructor called"
Vector v2(9, 5); // print "Constructor called"
Vector v3 = v1; // print "Copy Constructor called"
return 0;
}
退出Destructor called
时,main()
将在此案例中打印3次。
为了检查以上3点,我一直在玩dumb_display()
功能,更改形式参数/返回值的类型。在这样做的过程中,我对实际发生的事情感到困惑。
Vector dumb_display(Vector v)
{
Vector test(45, 67);
cout << "In dumb_display() function" << endl;
cout << v << endl;
return v;
}
下面:
每次按值返回传递的参数,如上面的函数(由值或引用传递的参数),复制构造函数被调用。
每次我们返回函数体中定义的对象(例如,return v;
更改return test;
)时,都不会调用复制构造函数。
我很难尝试理解这种行为。
我不知道这是否正确,但我认为(因为在函数调用期间创建了一次自动存储持续时间对象)一旦test
被创建,它就不会出现。必须再次创建,因为对象&#34;已经存在&#34;。这带来了一个问题:
为什么返回传递的参数会调用复制构造函数两次?为什么在调用函数期间必须创建两次相同的对象?
答案 0 :(得分:0)
#include <vector>
#include <type_traits>
#include <tuple>
#include <iostream>
using namespace std;
struct S {
S(){
cout << "default constructor" << endl;
}
S(S const &) {
cout << "copy constructor" << endl;
}
S(S &&) {
cout << "move constructor" << endl;
}
S & operator=(S const &) {
cout << "copy assignment" << endl;
return *this;
}
S & operator=(S &&) {
cout << "move assignment" << endl;
return *this;
}
};
S f() {
S s2;
cout << "In f()" << endl;
return s2;
}
S f2(S s) {
cout << "In f2()" << endl;
return s;
}
int main() {
cout << "about to call f" << endl;
S s2 = f();
(void)s2;
cout << endl << "about to call f2" << endl;
S s3 = f2(s2);
(void)s3;
}
结果:
about to call f
default constructor
In f()
about to call f2
copy constructor
In f2()
move constructor
在f()
中,对象是默认构造的,并且返回值优化用于实际构建它实际上最终的位置 - 在main中的s2变量中。不会调用复制/移动构造函数。
在f2()
中,为该函数的输入参数创建一个副本。然后将该值移入main中的变量s3,再次使用返回值优化。
直播:https://wandbox.org/permlink/kvBHBJytaIuPj0YN
如果您关闭返回值优化,您会看到您对图书所说的结果:
直播:https://wandbox.org/permlink/BaysuTYJjlJmMGf6
以下是没有move
运算符的两个示例,如果这让您感到困惑:
直播:https://wandbox.org/permlink/c0brlus92psJtTCf
并且没有返回值优化:
直播:https://wandbox.org/permlink/XSMaBnKTz2aZwgOm
它是相同数量的构造函数调用,只使用(可能更慢)复制构造函数而不是移动构造函数。
答案 1 :(得分:-1)
复制构造函数被调用两次,因为它首先从函数复制到temprary值(由函数调用表示并且是返回值,然后复制到变量中,需要两个副本。因为这是效率不高,还有一个“移动”构造函数,只需要一次。