面试题答案
一键面试初始化顺序带来的问题
- 未定义行为:C++标准仅保证在同一个翻译单元(源文件)内全局变量的初始化顺序是按照定义顺序进行的。但对于不同翻译单元中的全局变量,初始化顺序是未定义的。如果
A.cpp
中的a
依赖B.cpp
中的b
进行初始化,而b
未初始化时a
就尝试使用它,会导致未定义行为,程序可能崩溃或出现难以调试的错误。 - 依赖倒置:可能出现循环依赖的情况,例如
A.cpp
中的变量依赖B.cpp
中的变量,而B.cpp
中的变量又依赖A.cpp
中的变量,这会导致初始化死锁,程序无法正常启动。
解决方法
单例模式
- 设计思路:将需要初始化的全局变量封装在单例类中。单例类确保只有一个实例存在,并且在第一次使用时进行初始化。这样可以控制初始化顺序,避免不同翻译单元全局变量初始化顺序问题。
- 关键代码示例:
// Singleton.h
class Singleton {
public:
static Singleton& getInstance() {
static Singleton instance;
return instance;
}
// 假设这里的value就是需要的全局变量
int value;
private:
Singleton() : value(0) {}
~Singleton() {}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
在其他源文件中使用:
// SomeOtherFile.cpp
#include "Singleton.h"
void someFunction() {
Singleton& s = Singleton::getInstance();
// 使用s.value
}
静态局部变量
- 设计思路:在函数内部使用静态局部变量。静态局部变量在第一次进入函数时初始化,利用这一特性,可以将全局变量的初始化逻辑封装在函数中,通过调用函数来获取初始化后的变量,从而控制初始化顺序。
- 关键代码示例:
// GlobalVar.h
int& getGlobalVar() {
static int globalVar = 0; // 假设这里进行初始化逻辑
return globalVar;
}
在其他源文件中使用:
// AnotherFile.cpp
#include "GlobalVar.h"
void anotherFunction() {
int& var = getGlobalVar();
// 使用var
}