探秘对象构造和析构(一)

首先我们先看我们的类代码:

class Test
{
public:
	//带一个整型参数的构造函数
	Test(int a = 10) :ma(a) 
	{ cout << "Test(int)" << endl; }
	//析构函数
	~Test() 
	{ cout << "~Test()" << endl; }
	//拷贝构造函数
	Test(const Test &t) :ma(t.ma) 
	{ cout << "Test(const Test&)" << endl; }
	//赋值函数
	Test& operator=(const Test &t)
	{
		cout << "operator=" << endl;
		ma = t.ma;
		return *this;
	}
private:
	int ma;
};

再来看我们的main函数:

int main()
{
	//调用test(int)构造
	Test t1;
	//调用拷贝构造
	Test t2(t1);
	//调用拷贝构造
	Test t3 = t1;
	/* 这里Test(20)是显式生成临时对象 但是C++编译器在生成新对象的时候会对临时对象进行优化,减少开销 这里其实就t4(20); */
	Test t4 = Test(20); 
	cout << "--------------" << endl;
	//相当于调用了t4的operator =函数,其中t2是参数
	t4 = t2;
	/* 1.这里先显式的调用构造函数,Test(int),30是参数 2.然后调用operator=,临时对象是参数 3.临时对象析构 */
	t4 = Test(30);
	// 这是隐式生成临时对象,相当于int -> Test(int),其他步骤和显式一样的
	t4 = (Test)30;

	//这个也是隐式生成,相当于int -> Test(int),其他步骤和显式一样的
	t4 = 30; 
	
	cout << "--------------" << endl;
	//先构造一个临时对象,然后析构,p此时是失效指针
	Test *p = &Test(40);
	//这里,临时对象和引用结合,相当于临时对象有了别名(ref),生存期被延长了
	const Test &ref = Test(50);
	cout << "--------------" << endl;
	return 0;
}

运行结果:

Test(int)
Test(const Test&)
Test(const Test&)
Test(int)
--------------
operator=
Test(int)
operator=
~Test()
Test(int)
operator=
~Test()
Test(int)
operator=
~Test()
--------------
Test(int)
~Test()
Test(int)
--------------
~Test()
~Test()
~Test()
~Test()
~Test()

构造顺序

先看类代码:

class Test
{
public:
	// Test() Test(10) Test(10, 10)
	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;
};

再看main函数代码:

Test t1(10, 10); // 第一个构造,调用Test(int, int)
int main()
{
	Test t2(20, 20); // 第三个构造,调用Test(int, int)
	Test t3 = t2; // 第四个构造,调用Test(const Test&)
	// 静态关键字只有被用到才会构造,相当于static Test t4(30, 30);
	static Test t4 = Test(30, 30); // 第五个构造,调用Test(int, int),临时对象被优化了
	t2 = Test(40, 40); // 第六个,Test(int, int) operator= ~Test()
	// 这个看第二个参数,也就是第二个50,相当于(50, 50) = (Test)50; Test(int)
	t2 = (Test)(50, 50); // 第七个,Test(int,int) operator= ~Test()
	t2 = 60; //Test(int) 第八个,Test(int,int) operator= ~Test()
	Test *p1 = new Test(70, 70); // 第九个, Test(int,int) 
	Test *p2 = new Test[2]; // 第十个,相当于两次 Test(int,int) Test(int,int)
	Test *p3 = &Test(80, 80); // 第十一个 Test(int,int) ~Test()
	const Test &p4 = Test(90, 90); // 第十二个 Test(int,int)
	delete p1; // 析构~Test()
	delete[]p2; // 析构两次~Test() ~Test()
}
Test t5(100, 100); // 第二个调用,调用Test(int, int)

构造顺序和析构顺序相反。
全局变量永远都比main函数先行构造,想知道原因可以去看我的程序员的自我修养博客专栏,C++相关问题。
运行结果:

Test(int, int)
Test(int, int)
Test(int, int)
Test(const Test&)
Test(int, int)
Test(int, int)
operator=
~Test()
Test(int, int)
operator=
~Test()
Test(int, int)
operator=
~Test()
Test(int, int)
Test(int, int)
Test(int, int)
Test(int, int)
~Test()
Test(int, int)
~Test()
~Test()
~Test()
~Test()
~Test()
~Test()
~Test()
~Test()
~Test()

参考文献

[1] 施磊.腾讯课堂——C++高级.图论科技,2020.7.