一般的对象实例化在什么时候实例化的呢?
是不是在main函数运行到那里的时候,然后创建对象,会调用类里面的构造函数。
那当我们遇到全局/静态对象的时候,它是不是也是需要在main函数里面慢慢构造呢?
答案是 :
不是的。
全局/静态对象 的构造函数调用实在main函数之前的。
有人在疑问?main函数之前还有函数?不是从main函数开始运行的吗?
全局对象所在的内存地址空间为全局数据区,而局部对象的内存地址空间在栈中,他们触发构造函数和析构函数时机不同。

全局/静态对象构造函数实现:

在启动函数mainCRTStartup中有个_cinit,全局对象的构造函数就是在此函数中实现的,
在函数_cinit的_initterm函数调用中,初始化了全局对象。_initterm实现代码片段如下:

while(pfbegin<pfend){//pfbegin==_xc_a  pfend==_xc_zif(*pfbegin!=NULL)(**pfbgin)()//调用每一个初始化或构造代理函数++pfbegin;
}

当pfbegin不为NULL时进入if语句块。执行(**pfbegin)();
后并不会进入全局对象的构造函数中,而是进入编译器提供的构造代理函数中,由一个负责全局对象的构造代理函数完成对全局构造函数的调用过程。

构造代理函数代码如下:


由于构造函数需要传递对象的首地址作为this指针,而且构造函数可以带各类参数,因此编译器将为每个全局对象生成一段传递this指针和参数的代码,然后使用无参的代理函数去调用构造函数。

全局/静态对象析构函数实现:
全局/静态对象相同,其构造函数在函数_cinit的第二个_initterm调用中被构造。他们的析构函数的调用时机是在main函数执行完毕之后。既然构造函数出现在初始化过程中,对应的析构函数就会出现在程序结束出。我们来看一下mainCRTStartup函数,它在调用main函数结束后使用了exit用来终止程序,如下:

mainret=main(_argc,_argv,_environ);
//WPRFLAG//_WINMAIN_
exit(mainret);

在main函数调用结束后,由exit来结束进程,从而终止程序的运行。全局对象的析构函数的调用也在其中,由exit函数内的doexit实现,关键代码如下:

if(_onexitbegin)//_onexitbegin为函数指针数组的首地址
{_PVFV * pfend=_onexitend; //__onexitbegin为函数指针数组的尾地址
while(--pend >=__onexitbegin)//从后向前依次释放全局对象if(*pend!=NULL)(**pend)();//调用数组中保存的函数
}

__onexitbegin指向一个指向数组,该数组中保存着各类资源释放时的函数的首地址。编译器实在何时生成这样一个数组的呢?
全局构造函数的调用是在_cinit函数的第二个_initterm函数内完成,而在第二个_initterm函数的初始化函数指针数组。在执行每个全局对象构造代理函数时都会执行对象的构造函数,然后使用atexit注册析构代理函数。

举例:
如果定义一个全局对象CMyString G_MyStringTwo;,该对象的全局析构函数代理函数的分析如下所示:
;该代理函数由编译器添加,无源码对照
;函数入口对照

mov  ecx ,offset g_MyStringTwo(0042af7c)
call @ILT+35(MyStringTwo::~MyStringTwo)(00401028)
;函数退出部分
ret

由于函数数组中保存的析构代理函数被定义为无参函数,因此在调用析构函数时无法传递this指针。于是编译器需要为每个全局变量和静态对象建立一个中间代理的析构函数,用于传入全局对象的this指针。

2020-12-14(全局/静态对象的构造函数和析构函数调用的时机以及地址)相关推荐

  1. C++中构造函数和析构函数调用的时机

    今天看书忽然对这个地方有点模糊,尤其是析构函数在调用默认的析构函数和用户自己覆写的析构函数的时候有点意识模糊呢.写段代码总结下 [cpp]  view plain copy #include < ...

  2. java没有指针和析构所以_Java程序员学习C++之构造函数和析构函数调用的时机

    今天看书忽然对这个地方有点模糊,尤其是析构函数在调用默认的析构函数和用户自己覆写的析构函数的时候有点意识模糊呢.写段代码总结下 #include usingnamespacestd; classBox ...

  3. Qt之Q_GLOBAL_STATIC创建全局静态对象

    概述 所谓的全局静态对象,大多是在单例类中所见,之前写过一篇文章介绍如何实现一个单例类,在这里,这是最常见的方式来进行创建,需要自定义 static 类对象, 并进行手动初始化.而今天要说的是更简单的 ...

  4. qt -- Q_GLOBAL_STATIC创建全局静态对象

    创建一个全局静态对象,类型为QGlobalStatic,名称为VariableName,行为像一个指向type的指针. Q_GLOBAL_STATIC创建的对象在第一次使用时初始化自己,这意味着它不会 ...

  5. C++构造函数和析构函数调用虚函数时都不会使用动态联编

    先看一个例子: #include <iostream> using namespace std;class A{ public:A() {show();}virtual void show ...

  6. C++继承中构造函数、析构函数调用顺序及虚析构函数

    首先说说构造函数,大家都知道构造函数里就可以调用成员变量,而继承中子类是把基类的成员变成自己的成员,那么也就是说子类在构造函数里就可以调用基类的成员了,这就说明创建子类的时候必须先调用基类的构造函数, ...

  7. C++ 类继承:构造函数与析构函数调用顺序,派生类和基类之间的特殊关系,公有继承及其他

    文章目录 一.派生类构造函数与基类构造函数 二.创建与销毁派生类对象时,构造函数和析构函数的调用 三.派生类和基类之间的特殊关系 四.公有继承 (一).何为公有继承 (二).多态公有继承 (三).虚函 ...

  8. (二十三:2020.12.14)CVPR 2020 学习(二)《U^2 Net》

    <U^2 Net: Going Deeper with Nested U-Structure for Salient Object Detection><借助嵌套U型结构深入研究显着 ...

  9. 基于代价函数小波脊相位的MFSK信号符号速率估计MATLAB仿真及代码(2020.12.14更新)

    算法来源 王勇, 王李福, 邹辉,等. 一种小波脊相位提取方法: 中国专利. 仿真结果 引言 当前,脊点的选取较准确也较经典的方法是Liu等提出的里程碑式的基于代价函数的小波脊相位提取方法(即代价函数 ...

最新文章

  1. MSLicensing​中断远程桌面连接
  2. 微信公众号签名错误 invalid signature
  3. 【干货】容器适配器实现两个栈模拟队列
  4. 如何将字典值写入一个文本文件?
  5. NSPredicate 谓词
  6. Magento 获取系统设置 How to get data from Magento System Configuration
  7. mysql的utf8与utf8mb4 异同;utf8mb4_unicode_ci 与 utf8mb4_general_ci 如何选择
  8. Developer Express 之 XtraReport如何动态绑定数据
  9. 1.2w星!火爆GitHub的Python学习100天刷爆朋友圈!
  10. Mysql中有哪些数据类型(建议收藏)
  11. 【游戏开发实战】Unity UGUI序列帧动画(蓝胖子序列帧图)
  12. Unity修改编辑器
  13. 2022年盐城市“黄海明珠人才计划”领军人才项目申报奖励补贴条件
  14. Python herhan学习 day2
  15. 第九周项目六 委派任务
  16. 第十章《日期与时间》第6节:ZoneId、ZoneRegion和ZoneOffset
  17. saltstack内置执行模块列表
  18. 2022建筑设计企业申报建筑设计资质流程
  19. 柠檬班学习性能测试day2_性能测试入门(0519)
  20. 什么是泛型中的限定通配符和非限定通配符 ?

热门文章

  1. CV:计算机视觉技术之图像基础知识(二)—以python的skimage和numpy库来了解计算机视觉图像基础(图像存储原理-模糊核-锐化核-边缘检测核,进阶卷积神经网络(CNN)的必备基础)
  2. 成功解决The scripts freeze_graph.exe, saved_model_cli.exe, tensorboard.exe, tflite_convert.exe, toco.exe
  3. Py之gensim:gensim的简介、安装、使用方法之详细攻略
  4. Linux之apt-get:apt-get的简介、安装、使用方法之详细攻略
  5. DL之ANN/DNN: 人工神经网络ANN/DNN深度神经网络算法的简介、应用、经典案例之详细攻略
  6. ExecutableNotFound: failed to execute ['dot', '-Tsvg'], make sure the Graphviz executables are on yo
  7. PAT_B_1006 换个格式输出整数
  8. CH5E02 花店橱窗【线性DP】
  9. 函数中返回char *类型
  10. Linux系统新建用户用ssh远程登陆显示-bash-4.1$