【C++】构造函数、析构函数在局部、静态以及全局的调用和释放顺序

欢迎来到CILMY23的博客

本篇主题为: 构造函数、析构函数在局部、静态以及全局的调用和释放顺序

个人主页:CILMY23-CSDN博客

系列专栏:Python | C++ | C语言 | 数据结构与算法

感谢观看,支持的可以给个一键三连,点赞关注+收藏。


目录

一、局部域中的调用和释放顺序

二、局部和静态 

 三、局部变量、全局变量、静态变量的生命周期和析构顺序


写在前头:在讲解构造函数和析构函数在局部、全局、静态的顺序前,我们先回顾一下C/C++中的内存管理

 本篇主要研究静态区(数据段),局部,和全局之间的调用顺序,并且以学生类为例进行测试。


一、局部域中的调用和释放顺序

为了让学生类能够被我们调用和释放的时候识别,我们将做一些优化:

我们使用全缺省的构造函数来进行区分,给予ID值

class Student
{
public:
	Student(int ID = 1)
	{
		_ID = ID;
		cout << "Student()" << _ID << endl;
	}
	~Student()
	{
		cout << "~Student()" << _ID << endl;
	}
private:
	int _ID;
};

在main域里:

int main()
{
	Student stu1(1);
	Student stu2(2);
	Student stu3(3);

	return 0;
}

结果:

解释:

int main()中的对象创建顺序:

  1. 首先 main 函数开始执行,stu1和stu2,stu3会在创建时调用对应的构造函数。
  2. 这些局部变量在 main 函数结束时会自动销毁,它们会自动调用对应的析构函数,析构函数会在 main 的作用域结束后被调用。

因此顺序是:

main 函数开始 --> stu1 构造 --> stu2 构造 -->stu3 构造 --> main 函数结束 --> stu3 析构 --> stu2 析构 -->stu1 析构

我们发现后定义的会先析构,满足"后进先出",构造的顺序是从先定义先构造, 

二、局部和静态 

 我们现在将 stu3 对象加上关键字 staticstatic 会影响 stu3 对象的生命周期,它是一个静态变量,分配在全局/静态数据区域。它的生命周期从第一次进入其定义的作用域开始,并在程序终止时结束。

int main()
{
	Student stu1(1);
	Student stu2(2);
	static Student stu3(3);

	return 0;
}

结果:

我们发现,局部优先调用对应的析构函数,满足“后定义先析构”,静态则是最后调用对应的析构函数进行资源清理。 

 那如果涉及一个函数呢?

void func()
{
	Student stu3(3);
	static Student stu4(4);
}

int main()
{
	Student stu1(1);
	Student stu2(2);
	func();

	return 0;
}

结果:

解释: 

int main()中的对象创建顺序:

  1. 首先 main 函数开始执行,stu1和stu2会在创建时调用对应的构造函数。(这些局部变量在 main 函数结束时会自动销毁,它们会自动调用对应的析构函数,析构函数会在 main 的作用域结束后被调用。)
  2. 然后是调用func()函数,在 func 函数中,创建了两个 Student 对象:stu3 和 stu4。
  • 局部对象stu3 是一个局部变量,(它在 func 的作用域内创建,并在 func 结束时销毁)
  • 而 stu4 是一个静态变量,这意味着它的生命周期从首次创建开始,持续到程序结束。其构造函数在 func 首次调用时被执行,而析构函数直到程序结束才会被调用。 

因此顺序是:

main 函数开始 --> stu1 构造 --> stu2 构造 --> func 被调用 --> stu3 构造 --> stu4 构造 --> func 结束 --> stu3 析构 --> main 函数结束 --> stu1 析构 --> stu2 析构 --> 程序结束--> stu4 析构 

所以,如果有函数还是一样的,局部会优先调用对应的析构函数,满足"后进先出"静态最后调用析构函数

 三、局部变量、全局变量、静态变量的生命周期和析构顺序

 我们分别在函数的定义前后都增加了全局对象,stu5 , stu7,静态对象 stu6

Student stu5(5);
static Student stu6(6);

void func()
{
	Student stu3(3);
	static Student stu4(4);
}

Student stu7(7);

int main()
{
	Student stu1(1);
	Student stu2(2);
	func();

	return 0;
}

结果:

 

 解析:

全局域: 

  • Student stu5(5):这是在全局范围内的对象,在程序开始时就会创建,直到程序结束时才销毁。
  • static Student stu6(6):这是一个全局静态对象,它的构造函数会在程序开始时调用,它的生命周期与程序相同,直到程序结束时才销毁。
  • Student stu7(7):这个对象在全局范围内,和 stu5 类似,在程序开始时创建,在程序结束时销毁。

main 函数域:

  • Student stu1(1)Student stu2(2):这是在 main 函数中的局部变量,它们在 main 函数开始时创建,并在 main 结束时销毁。

func 函数域:

  • Student stu3(3):这是 func 函数中的局部变量,它的构造函数在 func 被调用时创建,并在 func 结束时销毁。
  • static Student stu4(4):这是 func 中的静态变量,它的构造函数在 func 第一次调用时创建,并在程序结束时销毁。

因此顺序是:

stu5 构造 --> stu6 构造 --> stu7 构造 --> main 函数开始 --> stu1 构造 --> stu2 构造 --> func 被调用 --> stu3 构造 --> stu4 构造 --> func 结束 --> stu3 析构 --> main 函数结束 --> stu2 析构 --> stu1 析构 --> 程序结束--> stu4 析构 --> stu7 析构 --> stu6 析构 --> stu5 析构 


总结: 

  •  在局部域中,后定义的先析构,满足"后进先出",先定义的先构造
  •  局部和静态:局部优先调用对应的析构函数,满足"后进先出"静态最后调用析构函数
  •  局部,静态,全局:构造顺序是从 全局、静态 --> 局部、静态,析构顺序是 局部  --> 全局、静态("后进先出"

感谢各位同伴的支持,本期构造函数、析构函数、静态函数以及全局的调用和释放顺序就讲解到这啦,如果你觉得写的不错的话,可以给个一键三连,点赞关注+收藏,若有不足,欢迎各位在评论区讨论。   

  • 44
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值