面试题答案
一键面试初始化顺序分析
- 全局变量:在程序启动时,全局变量(包括
GlobalVar
)会首先进行初始化。但此时GlobalClass1
还未实例化,staticLocalVar
也未初始化。 GlobalClass1
的构造函数:GlobalClass1
实例化时,其构造函数会被调用,进而调用globalFunction
。在globalFunction
中会使用GlobalVar
,此时GlobalVar
已初始化。staticLocalVar
:当第一次执行到包含staticLocalVar
的代码块时,staticLocalVar
才会初始化,且依赖于GlobalClass1
实例化后的成员函数返回值。但在GlobalVar
初始化时,GlobalClass1
可能还未实例化,这就导致了潜在的初始化顺序问题。
可能出现的问题
- 未定义行为:如果
GlobalVar
在初始化时需要访问GlobalClass1
实例化后的成员函数返回值(因为staticLocalVar
依赖于此,而GlobalVar
所在源文件包含staticLocalVar
),但此时GlobalClass1
还未实例化,就会产生未定义行为。 - 初始化失败:
staticLocalVar
依赖于GlobalClass1
实例化后的成员函数返回值,若在其初始化时GlobalClass1
未实例化完全或者相关成员函数状态不正确,可能导致staticLocalVar
初始化失败。
解决方案
- 延迟初始化:将
GlobalVar
和staticLocalVar
的初始化推迟到需要使用它们的时候,而不是在程序启动时。例如,可以将GlobalVar
封装在一个函数内,在函数内进行初始化,并返回其引用。对于staticLocalVar
也采用类似方式,确保在GlobalClass1
完全实例化且状态正确后再进行初始化。
class GlobalClass1 {
// 类定义...
public:
int getValueForStaticLocalVar() {
// 返回合适的值用于 staticLocalVar 的初始化
return 42;
}
};
GlobalClass1 globalObj;
// 延迟初始化 GlobalVar
int& getGlobalVar() {
static int GlobalVar = 0;
return GlobalVar;
}
// 延迟初始化 staticLocalVar
int& getStaticLocalVar() {
static int staticLocalVar = globalObj.getValueForStaticLocalVar();
return staticLocalVar;
}
- 单例模式:使用单例模式确保
GlobalClass1
只有一个实例,并且在第一次使用时进行初始化。同时,在单例类中管理GlobalVar
和staticLocalVar
的初始化,保证它们在合适的时机进行初始化。
class GlobalClass1 {
private:
static GlobalClass1* instance;
int valueForStaticLocalVar;
GlobalClass1() : valueForStaticLocalVar(42) {}
public:
static GlobalClass1* getInstance() {
if (instance == nullptr) {
instance = new GlobalClass1();
}
return instance;
}
int getValueForStaticLocalVar() {
return valueForStaticLocalVar;
}
};
GlobalClass1* GlobalClass1::instance = nullptr;
// 使用单例模式管理 GlobalVar
int& getGlobalVar() {
static int GlobalVar = 0;
return GlobalVar;
}
// 使用单例模式管理 staticLocalVar
int& getStaticLocalVar() {
static int staticLocalVar = GlobalClass1::getInstance()->getValueForStaticLocalVar();
return staticLocalVar;
}
通过以上两种方式,可以有效避免由于初始化顺序不当导致的问题。