C++编程规范之21:避免跨编译单元的初始化依赖

简介:

摘要:

    保持顺序,不同编译单元中的名字空间级对象决不应该在初始化上互相依赖,因为其初始化顺序是未定义的。这样做会惹出很多麻烦,轻则在项目中稍做修改就会引发奇怪的崩溃,重则出现严重的不可移植问题——即使是同一编译器的新版本也不行。

    在不同的编译单元中定义两个名字空间级的对象时,先调用哪一个对象的构造函数是没有定义的。经常工具可能会碰巧按照编译单元目标文件的连接顺序初始化,但这种假设并不总是可靠的;即使确实如此,你总不会希望自己的代码的正确性难以捉摸地依赖于makefile或者项目文件吧。

    因此,在任何名字空间级对象的初始化代码中,不能假设其他编译单元中定义的任何其他对象都已经初始化了。这些考虑方法也适用于动态初始化的原始类型变量。

    请注意,甚至在使用构造函数构造之前,名字空间级对象就已经使用0静态初始化过了。有些自相矛盾的是,这种零初始化会使错误更难以检查,因为静态的零初始化不会迅速使程序崩溃,而是使未初始化对象显现出一种看似合理的表象。你可能认为字符串是空的,指针是空的,整数型变量为0,而事实上,代码已经费劲地将它们初始化了。

    为了避免这一问题,应该尽可能地避免使用名字空间级的变量,它们很危险。如果确实需要可能依赖于另一个变量的此种变量,可以考虑使用singleton设计模式。使用时要小心一些,可以通过确保对象在第一次访问时被初始化,来避免隐含的依赖性。Singleton本质上也是全局变量,它会因为相互依赖或者循环依赖而被破坏。

相关文章
|
2月前
|
自然语言处理 编译器 Linux
|
2月前
|
自然语言处理 编译器 Linux
告别头文件,编译效率提升 42%!C++ Modules 实战解析 | 干货推荐
本文中,阿里云智能集团开发工程师李泽政以 Alinux 为操作环境,讲解模块相比传统头文件有哪些优势,并通过若干个例子,学习如何组织一个 C++ 模块工程并使用模块封装第三方库或是改造现有的项目。
|
3月前
|
存储 程序员 编译器
简述 C、C++程序编译的内存分配情况
在C和C++程序编译过程中,内存被划分为几个区域进行分配:代码区存储常量和执行指令;全局/静态变量区存放全局变量及静态变量;栈区管理函数参数、局部变量等;堆区则用于动态分配内存,由程序员控制释放,共同支撑着程序运行时的数据存储与处理需求。
185 22
|
3月前
|
Linux 编译器 C语言
Linux c/c++之多文档编译
这篇文章介绍了在Linux操作系统下使用gcc编译器进行C/C++多文件编译的方法和步骤。
53 0
Linux c/c++之多文档编译
|
3月前
|
存储 编译器 数据安全/隐私保护
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解2
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
47 3
|
3月前
|
编译器 C++
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解1
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
58 3
|
3月前
|
C++
【C++】深入探索类和对象:初始化列表及其static成员与友元(二)
【C++】深入探索类和对象:初始化列表及其static成员与友元
|
3月前
|
算法 编译器 C++
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
100 2
|
3月前
|
编译器 C++
【C++】深入探索类和对象:初始化列表及其static成员与友元(三)
【C++】深入探索类和对象:初始化列表及其static成员与友元
|
3月前
|
C++
C++构造函数初始化类对象
C++构造函数初始化类对象
28 0