构造函数、复制构造函数、赋值运算符的调用
结合下面的例子来讨论三者的调用顺序
#include <iostream>
#include <vector>
using namespace std;
class Foo {
public:
Foo() {
cout << "Foo constructor" << endl;
}
Foo(const Foo&) {
cout << "Foo copy constructor" << endl;
}
Foo& operator= (const Foo&) {
cout << "Foo operator =" << endl;
return *this;
}
~Foo() {
cout << "Foo destructor" << endl;
}
};
int f(Foo) {
return 0;
}
int g(const Foo&) {
return 0;
}
Foo h() {
Foo foo;
return foo;
}
int main(void) {
Foo vf1; //1
f(vf1);//2
g(vf1);//3
Foo vf2 = vf1;//4
vf2 = h();//5
Foo *pf = new Foo();//6
delete pf;//7
vector<Foo> vecf(3);//8
return 0;
}
- 1:调用无参构造函数,故:Foo constructor。
- 2:向函数f传入刚才构造的对象vf1,函数结束值vf1要销毁。故:Foo copy constructor,Foo destructor
- 3:由于g函数的形参是引用,故不会调用构造函数
- 4:由于定义对象,并对此对象用产生的对象进行复制(建立一个新的对象,并用另外一个对象进行初始化),故:Foo copy constructor
- 5:若编译器不做优化,执行结果:h函数先创建对象,即Foo constructor;返回此对象时,故会创建临时对象,并对此对象进行复制,即Foo copy constructor;执行完以后,h函数结束作用域,foo对象销毁,即Foo destructor;由于只是赋值,并没有定义新的对象,调用赋值运算符,即Foo operator =;最后临时变量的使命完成,进行销户;即Foo destructor。而编译器做优化以后,返回值优化的目的就是为了省去临时对象的创建和销毁的巨大开销,这种开销对程序员不可见,但是会潜在对程序性能产生很大影响。执行结果:Foo constructor,Foo operator =,Foo destructor 。返回值优化具体详细细节见https://blog.csdn.net/hycxag/article/details/82999739
- 6:堆上new一个Foo对象,即:Foo constructor
- 7:delete删除对应new分配的对象,即:Foo destructor
- 8:当我们声明一个具有初始长度的类容器的时候,编译器会自动调用该类的构造函数对容器进行初始化,所以一般会认为产生3个Foo constructor的输出。实际上,这里的过程是首先生成一个临时对象,然后以该临时对象为蓝本进行copy,即调用3次复制构造函数将临时对象复制到容器中的每个元素,这时临时对象已经完成其使命,因而编译器调用析构函数将其释放,即:Foo constructor,Foo copy constructor,Foo copy constructor,Foo copy constructor,Foo destructor