定义在不同编译单元的全局变量,初始化顺序不固定;定义在同一编译单元内的全局变量,初始化顺序与定义顺序保持一致。
**问题分析**
C++ 对”定义于不同编译单元内的 non-local 对象“ 的初始化次序无明确定义,所以当某个编译单元内的 non-local 对象的初始化操作依赖了另一个编译单元内的 non-local 对象,可能因初始化顺序导致异常情况发生。下面举一个例子:
```c++
// file_system.h
class FileSystem {
public:
FileSystem(int* p_size) : _p_size(p_size) {
printf("tfs init.\n");
}
int size() const {
return *_p_size;
}
private:
int* _p_size;
};
// file_system.cpp
extern Dick dic;
FileSystem tfs(dic.p_size());
// directory.h
class Directory {
public:
Directory();
int size() const;
private:
int _size;
};
class Dick {
public:
Dick();
int* p_size() const;
private:
int* _p_size;
};
// directory.cpp
int maxn = 100;
extern FileSystem tfs;
Directory::Directory() {
_size = tfs.size();
printf("dir init\n");
}
int Directory::size() const {
return _size;
}
Dick::Dick() {
_p_size = &maxn;
printf("dic init\n");
}
int* Dick::p_size() const {
return _p_size;
}
Directory dir;
Dick dic;
// main.cpp
extern Directory dir;
int main () {
printf("%d\n", dir.size());
return 0;
}
```
这里一共三个编译单元,dir 和 dic 两个变量在同一个编译单元内,在同一编译单元内,全局变量初始化顺序按照定义顺序,所以 dir 的初始化操作在 dic 前,而 dir 初始化依赖 tfs,tfs 变量的初始化依赖 dic。这里虽然是主动实现一个依赖循环,但是这也说明了一个问题,全局变量的初始化操作顺序是不明确的。
**解决方案**
为了避免全局变量初始顺序不明确导致的问题,最好避免全局变量的初始化操作依赖另一个编译单元的全局变量,或者把它们放到同一个编译单元内(因为同一个编译单元内的全局变量初始化顺序按照定义顺序)。如果无法避免,我们可以通过 Singleton 模式,将每个全局变量对象搬到自己的专属函数内,并且该对象在此函数内被声明为 static:
```c++
FileSystem& tfs() {
static FileSystem fs;
return fs;
}
```
- 目录
- 基础知识
- 1、变量和基础类型
- 1.1、内置类型
- 1.2、变量
- 1.3、复合类型
- 1.4、类型修饰符
- 1.5、类型处理
- 1.6、自定义结构
- 1.7、数组
- 2、表达式和语句
- 2.1、运算符
- 2.2、语句
- 3、函数
- 1、语法相关
- 2、资源管理
- 3、面向对象
- 4、模板与泛型编程
- Problem01:判断类中是否包含函数
- Problem02:解析函数的参数类型
- 5、系统库
- Problem01:多线程维护最大值
- Problem02:介绍一下strcpy、strncpy、memcpy、memmove
- Problem03:介绍一下网络编程
- Problem04:select、poll、epoll的区别
- 未整理
- Problem11:实现在main函数前、后执行的函数
- Problem12:可变参函数的实现
- Problem13:全局变量初始化顺序问题
- Problem14:介绍一下隐式转换
- Problem07:实现一个不能被拷贝的类
- Problem08:实现一个只能通过动态、静态分配的类
- 开源项目
- redis
- 第一部分 数据结构与对象
- redis 底层数据结构
- redis 对象
- taskflow
- 数据结构
- Executor
