关于对象生存周期的事儿~
先给大家看一个例子:
我们这里在,构造,拷贝,赋值,析构函数中打印相应的函数名,参数列表。
class Test
{
public:
Test(int a=5,int b=5):ma(a),mb(b)
{
cout << "Test(int,int)" << endl;
}
~Test()
{
cout << "~Test()" << endl;
}
Test(const Test &src):ma(src.ma),mb(src.mb)
{
cout << "Test(const Test&)" << endl;
}
void operator=(const Test &src)
{
ma = src.ma;mb = src.mb;cout << "operator=" << endl;
}
private:
int ma;
int mb;
};
Test t1(10, 10); //Test<int,int>
int main()
{
1 Test t2(20, 20); //Test<int,int>
2 Test t3 = t2; //Test<const Test&>
3 static Test t4 = Test(30, 30); //Test<int,int>
4 t2 = Test(40, 40);//Test<int,int>,operator=,~Test()
5 t2 = (Test)(50, 50);//Test<int,int>,operator=,~Test()
6 t2 = 60;//Test<int,int>,operator=,~Test()
7 Test *p1 = new Test(70, 70);//Test<int,int>
8 Test *p2 = new Test[2]; //Test<int,int>,Test<int,int>
9 Test *p3 = &Test(80, 80);//Test<int,int>,~Test()
10 Test &p4 = Test(90, 90);//Test<int,int>
11 delete p1; //~Test()
12 delete[]p2; //~Test(),~Test()
13 return 0;
}
以下是执行结果:
我们来看看,这些对象是怎么构造析构的
- main函数外先构造,即全局变量先构造
main中:
-main函数内顺序构造
- main中第二行,用对象初始化一个对象,调拷贝构造函数
- Test t4 = Test(30, 30);编译器优化。等同于Test T4(30,30)
- 4、5、6行,都是先构造临时对象,再赋值,再析构。(为什么不用拷贝?因为,赋值是以存在的对象,而拷贝是初始化)
- 9、10行:
9 Test *p3 = &Test(80, 80);//Test<int,int>,~Test(),要析构,//那我这个指针指向的是什么?
10 Test &p4 = Test(90, 90);//Test<int,int>//引用必须绑定有地址的,所以不可析构。
- 析构顺序与构造顺序相反,先析构main中再析构全局,
- 临时对象在拷贝同类型对象时不产生临时对象。
如何更高效?(减少函数调用) - 对象传递时,尽量选择引用传参,少了两个函数的调用;
- 返回一个对象时,最好直接返回一个临时对象,而不要先定义再返回。减少函数调用;
- 当我们接收返回值为对象时,以初始化接收,减少函数调用。