c++ 全局变量初始化的一点总结

对于C语言的全局和静态变量,不管是否被初始化,其内存空间都是全局的;如果初始化,那么初始化发生在任何代码执行之前,属于编译期初始化。由于内置变量无须资源释放操作,仅需要回收内存空间,因此程序结束后全局内存空间被一起回收,不存在变量依赖问题,没有任何代码会再被执行!

C++引入了对象,这给全局变量的管理带领新的麻烦。C++的对象必须有构造函数生成,并最终执行析构操作。由于构造和析构并非分配内存那么简单,可以说相当复杂,因此何时执行全局或静态对象(C++)的构造和析构呢?这需要执行相关代码,无法在编译期完成,因此C++标准规定:全局或静态对象当且仅当对象首次用到时才进行构造,并通过atexit()来管理对象的生命期,在程序结束之后(如调用exit,main),按FILO顺序调用相应的析构操作!

全局变量、文件域的静态变量和类的静态成员变量在main执行之前的静态初始化过程中分配内存并初始化;局部静态变量(一般为函数内的静态变量)在第一次使用时分配内存并初始化。这里的变量包含内置数据类型和自定义类型的对象。

函数内的静态对象,初始化是在第一次运行到那里的时候才初始化的。假设有一个函数testFun,大约是下面这样

void testFun()
{
static std::string str("Test string");
}

那么函数里面那个str,要第一次运行testFun的时候才会被初始化。

初始化的顺序

对于出现在同一个编译单元内的全局变量来说,它们初始化的顺序与他们声明的顺序是一致的(销毁的顺序则反过来),而对于不同编译单元间的全局变量,c++ 标准并没有明确规定它们之间的初始化(销毁)顺序应该怎样,因此实现上完全由编译器自己决定,一个比较普遍的认识是:不同编译单元间的全局变量的初始化顺序是不固定的,哪怕对同一个编译器,同一份代码来说,任意两次编译的结果都有可能不一样[1]。

因此,一个很自然的问题就是,如果不同编译单元间的全局变量相互引用了怎么办?

当然,最好的解决方法是尽可能的避免这种情况.

几个技巧

好吧,我承认总有那么一些特殊的情况,是需要我们来处理这种在全局变量的初始化函数里竟然引用了别的地方的全局变量的情况,比如说在全局变量的初始化函数里调用了 cout, cerr 等(假设是用来打 log, 注意 cout 是标准库里定义的一个全局变量)[2],那么标准库是怎样保证 cout 在被使用前就被初始化了呢? 有如下几个技巧可以介绍一下。

Construct On First Use

该做法是把对全局变量的引用改为函数调用,然后把全局变量改为函数内的静态变量:

int get_global_x()
{static X x;return x.Value();
}

这个方法可以解决全局变量未初始化就被引用的问题,但还有另一个对称的问题它却没法解决,函数内的静态变量也属于 variables with static storage, 它们析构的顺序在不同的编译单元间也是不确定的,因此上面的方法虽然必然能保证 x 的初始化先于其被使用,但却没法妥善处理,如果 x 析构了 get_global_x() 还被调用这种可能发生的情况。

一个改进的做法是把静态变量改为如下的静态指针:

int get_global_x()
{static X* x = new X;return x->Value();
}

这个改进可以解决前面提到的 x 析构后被调用的问题,但同时却也引入了另一个问题: x 永远都不会析构了,内存泄漏还算小问题或者说不算问题,但如果 x 的析构函数还有事情要做,如写文件清理垃圾什么的,此时如果对象不析构,显然程序的正确性都无法保证.

这个问题在 gcc c++ 的标准库里也没有得到解决,有兴趣的可以看看这个讨论。

--more

Storage duration

All objects in a program have one of the following storage durations:

  • automatic storage duration. The storage for the object is allocated at the beginning of the enclosing code block and deallocated at the end. All local objects have this storage duration, except those declared static, extern or thread_local.
  • static storage duration. The storage for the object is allocated when the program begins and deallocated when the program ends. Only one instance of the object exists. All objects declared at namespace scope (including global namespace) have this storage duration, plus those declared with static or extern.
  • thread storage duration. The storage for the object is allocated when the thread begins and deallocated when the thread ends. Each thread has its own instance of the object. Only objects declared thread_local have this storage duration. thread_local can appear together with static or extern to adjust linkage.

(since C++11)

  • dynamic storage duration. The storage for the object is allocated and deallocated per request by using dynamic memory allocation functions.
constexpr char kFoxSays[] = "Abay-ba-da bum-bum bay-do";

初始化没有顺序。一个全局变量可能指到另一个全局变量。但那个全局变量可能还有初始化或者已经end了。

各全局变量的析构函数是顺序调用的,与调用构造函数的顺序是相反的。这就保证做到“先构造的全局类变量后析构。”

Dynamic initialization is not ordered across translation units, and neither is destruction (except that destruction happens in reverse order of initialization).

When one initialization refers to another variable with static storage duration, it is possible that this causes an object to be accessed before its lifetime has begun (or after its lifetime has ended). Moreover, when a program starts threads that are not joined at exit, those threads may attempt to access objects after their lifetime has ended if their destructor has already run.

全局对象_C++全局变量初始化相关推荐

  1. node.js全局对象和全局变量

    概念:所有属性都可以在程序的任何地方访问,即全局变量.在JavaScript中,通常window是全局对象,而Node.js的全局对象是global,所有全局变量都是global对象的属性,如:con ...

  2. JavaScript读书笔记(三)布尔值,null,undefined,全局对象,包装对象

    参照内容来自<JavaScript权威指南> 布尔值 任意JavaScript的值都可以转换为布尔值. 部分值会被转换为false,其他转换为true. 会被转换为false的有:(1)u ...

  3. Node.js 全局对象

    Node.js 全局对象 在浏览器 JavaScript 中,通常 window 是全局对象, 而 Node.js 中的全局对象是 global,所有全局变量(除了 global 本身以外)都是 gl ...

  4. Node.js:get/post请求、全局对象、工具模块

    一.GET/POST请求 在很多场景中,我们的服务器都需要跟用户的浏览器打交道,如表单提交.表单提交到服务器一般都使用 GET/POST 请求. 1.获取GET请求内容 由于GET请求直接被嵌入在路径 ...

  5. 30.Node.js 全局对象

    转自:http://www.runoob.com/nodejs/nodejs-module-system.html 学习要点:  - __filename  - __dirname  - setTim ...

  6. node全局对象 文件系统

    node全局对象 js中一个对象,该对象为全局对象. 在客户端中,该对象为whindow,由this进行指向 node中的全局对象为global,所有的全局变量,除了自己以外都是global对象的属性 ...

  7. 一.node的事件处理;二.node的全局对象;三.node的readline模块;四.node的Web编程

    目录 一.node的事件处理 1.node采用的事件驱动模式来进行事件处理的:只有当事件被触发时才执行相关程序 2.node是单线程运行的:采用事件轮询方式,不断的查询事件队列中的消息,然后根据消息执 ...

  8. JS 全局对象 全局变量 作用域 (改自TOM大叔博文)

    JavaScript通过函数管理作用域. 局部变量:在函数内部声明的变量是局部变量,只能在这个函数内部使用,函数外部不可用. 全局变量:在任何函数外面声明的变量:或是未经声明在函数内部直接简单使用的变 ...

  9. nodejs 全局变量和全局对象

    1.全局对象 所有模块都可以调用 1)global:表示Node所在的全局环境,类似于浏览器中的window对象. 2)process:指向Node内置的process模块,允许开发者与当前进程互动. ...

最新文章

  1. Sublime text 2/3 [Decode error - output not utf-8] 完美解决方法
  2. 微软10亿美元砸入OpenAI:明为AGI,暗争谷歌,被指云计算换投资
  3. Linux 的启动流程
  4. 如何打造千万级Feed流系统?阿里数据库技术解读
  5. Swift之缓存文件处理
  6. openstack系列文章(二)
  7. html清除图片缓存
  8. 安卓开发基础面试题,Android面试必备的集合源码详解,附小技巧
  9. 爆炸的符卡洋洋洒洒(01背包)
  10. SQL 数据库 学习 033 视图
  11. CCF_Java_201909-3_字符画
  12. edge播放视频HTML5黑屏,Win10 edge 浏览器 播放视频黑屏解决方法
  13. 阿里云服务器遭ddos攻击防御案例
  14. vant 动态 粘性布局_使用 position:sticky 实现粘性布局
  15. 论文简介:Extract Line Art from Illustrations
  16. WPF 控件 (二、按钮)
  17. XMLHttpRequest——Level2
  18. Linux用户、组管理
  19. (翻译)文章列表(Article List)
  20. 《怪诞行为学》读书笔记

热门文章

  1. 32位CPU和64位CPU 区别
  2. 深度剖析Service Mesh服务网格新生代Istio
  3. JavaSE各阶段练习题----IO流
  4. 左神算法:加强堆的实现(Java)
  5. leetcode 385. Mini Parser | 385. 迷你语法分析器(Java)
  6. 操作系统:第一章 计算机系统概述
  7. Redis实战(五):Redis的持久化RDB、fork、copyonwrite、AOF、RDBAOF混合使用
  8. Java 开发环境配置 win10
  9. 分布式文件系统HDFS解析
  10. python快速学_python快速学习4