*【注】此为小白引导教程
【引入】C++中的全局对象什么时候执行构造函数?什么时候执行析构函数?与局部对象又有什么区别?
【正文】
对于小白(我也是小白)来说,学习C++类的时候很容易联系之前的所学的全局对象,猜测全局对象和局部对象哪个先构造哪个后析构,与其百度,不如自己去问编译器!
思路是这样的,我们先写一个类,一个有点简单“又不简单”的类
#include <string>
#include <iostream>
using std::string;
using std::cout;
using std::endl;
class A
{
public:
A(string s)
{
str.assign(s);
cout << str << ":A构造" << endl;
}
~A()
{
cout << str << ":A析构" << endl;
}
private:
string str;
};我们写一个类用作局部和全局对象的类型,自然要知道在哪里构造在哪里析构,于是加了个string作为private成员记录位置。
类写好了开始写测试程序主体
A test1("全局");
int main()
{
A test2("main");
return 0;
}编译执行,结果如图。
可以发现,全局对象先于局部对象构造,后于局部对象析构。
我们可以扩展代码(以下代码无法编译通过)
/***************
以下代码无法编译通过
***************/
#include <string>
#include <iostream>
using std::string;
using std::cout;
using std::endl;
class A
{
public:
A(string s)
{
str.assign(s);
cout << str << ":A构造" << endl;
}
~A()
{
cout << str << ":A析构" << endl;
}
string str;
};
//定义,假设不自动构造
A test1;
//构造
test1.A("全局");
int main()
{
//定义,假设不自动构造
A test2;
//构造
test2.A("main");
//析构(主动式)
test2.~A();
return 0;
}
//析构(主动式)
test1.~A();这样就便于理解了。
【扩展】
我们知道,在C/C++中结束程序不止有return,还有C stdlib.h中的exit(int)、abort(void),unistd.h中的_exit(int),C++的throw。
我们先来试下exit(int)
#include <stdlib.h>
int main()
{
...
exit(0);
}可以看到全局对象完整地构造析构,而main中的局部对象只完成了构造,未析构。
从exit(int)的特性来说,结果是正确的,exit(int)结束了main函数,并没有直接结束了程序,而全局对象储存在data数据段中由程序联立的运行时代码析构(对于小白来说姑且这么叫着)。
我们再来看_exit(0)
#include <unistd.h>
int main()
{
...
_exit(0);
}结果如图
我们可以看出,不管是全局还是局部对象,都并未析构,说明_exit(int)是直接结束了程序的进程,并未抛出异常。
我们再来看看会抛出异常的abort()
#include <stdlib.h>
int main()
{
...
abort();
}结果如图
可见abort()与_exit(int)的区别是会抛出异常!
好了,聊了这么久的C库函数,我们来看看C++的内置throw
int main()
{
...
throw;
}结果如图
至此,我们都应该了解了C++中的全局对象什么时候执行构造函数,什么时候执行析构函数,与局部对象又有什么区别。
小白教程就是在文章最后作者并不会总结,小白自己总结去吧!
【题外话】
在学编程时,我们不能总是去百度,问大神,编译器才是最好的老师,得自己去写点代码试下,看看结果,再自己推下结论,哪怕错了都没关系,重要的不是结果是过程。这篇文章的精华不在正文内容而是在这题外话。