C++和C的不同点之一在于C++通过类来定义对象,那么对象何时产生,是否需要释放呢???本篇文章将会针对对象的生命周期做出详细介绍。
关于对象的生命周期,我们需要了解类的构造函数,析构函数,拷贝构造函数,赋值运算符重载函数等等。(具体可以参照我的博文https://mp.csdn.net/postedit/89514819)。
首先我们给出以下代码:
#include<iostream>
using namespace std;
class Test
{
public:
Test(int a = 5,int b = 5):ma(a),mb(b) //拷贝构造函数
{cout<<"Test(int)"<<endl;}
~Test() //析构函数
{cout<<"~Test()"<<endl;}
Test(const Test &src):ma(src.ma),mb(src.mb) //拷贝构造函数
{cout<<"Test(const Test&)"<<endl;}
Test& operator=(const Test &src) //赋值运算符重载函数
{
cout<<"operator="<<endl;
ma = src.ma;
mb = src.mb;
return *this;
}
private:
int ma;
int mb;
};
Test t1(10,10);
int main()
{
Test t2(20,20);
Test t3 = t2;
static Test t4 = Test(30,30);
t2 = Test(40,40);
t2 = (Test)(50,50);
/*
构造函数只有一个参数的 Test(val) <====> (Test)val
构造函数有两个参数 Test(a,b) <====> (Test)b
析构顺序:局部对象 静态对象 全局对象
*/
t2 = 60;
Test *p1 = new Test;
Test *p2 = new Test[2];
Test *p3 = &Test(70,70); //指针和对象不是共用一块内存,当语句结束时,析构临时对象
Test &p4 = Test(80,80); //引用和对象是一块内存,语句结束时,不析构
delete p1;
delete []p2;
return 0;
}
Test t5(90,90);
执行结果:
Test(int) //普通构造t1
Test(int) //普通构造t5
Test(int) //普通构造t2
Test(const Test&) //t2拷贝构造t3
Test(int) //普通构造t4
Test(int) //普通构造临时对象
operator= //临时对象赋值t2
~Test() //析构临时对象
Test(int) //普通构造临时对象
operator= //临时对象赋值t2
~Test() //析构临时对象
Test(int) //普通构造临时对象(隐式生成)
operator= //临时对象赋值t2
~Test() //析构临时对象
Test(int) //普通构造p1指向的无名对象
Test(int) //普通构造p2指向的无名对象
Test(int) //普通构造p2指向的无名对象
Test(int) //普通构造临时对象
~Test() //析构临时对象
Test(int) //普通构造临时对象
~Test() //析构p1指向的无名对象
~Test() //析构p2指向的无名对象
~Test() //析构p2指向的无名对象
~Test() //析构p4指向的无名对象
~Test() //析构t3
~Test() //析构t2
~Test() //析构t4
~Test() //析构t5
~Test() //析构t1
我们对上面代码及其执行结果进行分析,可的如下结论:
- 对于全局对象,程序一开始,其构造函数就先被执行;程序即将结束前其析构函数将被执行。
- 对于局部对象,当对象诞生时,其构造函数被执行;当程序流程将离开该对象的声明周期时,其析构函数被执行。
- 对于静态(static)对象,当对象诞生时其构造函数被执行;当程序将结束时其析构函数才被执行,但比全局对象的析构函数早一步执行。
- 对于以new方式产生出来的局部对象,当对象诞生时其构造函数被执行,析构函数则在对象被delete时执行。时执行
扩展: