背景
C++ 中全局对象的初始化在 main 函数执行前完成,在 main 函数执行结束前销毁。在同一源码文件中全局变量的初始化顺序和其定义顺序一致;但在不同的源码文件中其初始化顺序不一致,就有可能导致代码出错。
一般解决方法
①.概述
静态局部变量只有在第一次使用时才会初始化,并且只会初始化一次,可应用该特点解决全局变量的初始化问题。
②.构造动态对象
demoClass & getDemo
{
static demoClass * demo = new demoClass();
return *demo;
}
该方法中,在程序结束时 demo 指向的内存会被系统强制回收,不会造成内存泄漏,但是由于其析构函数没有被调用,就有可能造成一些必要操作没有被执行,从而引发问题。
③.构造静态对象
demoClass & getDemo
{
static demoClass demo
return demo;
}
该方法中,demo 会在其所在的源码文件中的其他全局对象销毁时一起销毁,会执行析构函数,但由于不同源码文件间全局对象销毁顺序不一致,有可能引发问题。
Nifty Counter 惯用法
①.概述
Nifty Counter 惯用法的原理就是为全局变量创建一个管理对象,通过这个管理对象进行全局变量的创建和销毁。
②.代码示例
//demoClass.h
class demoClass
{
public:
demoClass() { std::cout << "demoClass construted " << std::endl; }
~demoClass() { std::cout << "demoClass deconstruted " << std::endl; }
void func(){ std::cout << "hello world " << std::endl; }
};
//demoClassInit.h
#include "demoClass.h"
extern demoClass* demo;
class demoClassInit
{
public:
explicit demoClassInit();
~demoClassInit();
static int demo_Counter;
};
static demoClassInit demoInit;
//demoClassInit.cpp
#include "demoClassInit.h"
demoClass* demo = nullptr;
int demoClassInit::demo_Counter = 0;
demoClassInit::demoClassInit()
{
if (demo_Counter++ == 0) demo = new demoClass;
}
demoClassInit::~demoClassInit()
{
if (--demo_Counter == 0) delete demo;
}
#include "demoClassInit.h"
int main()
{
demo->func();
return 0;
}
③.原理说明
在每个需要使用全局变量的源码文件中都必须引用头文件 “demoClassInit.h”,则一定会引入一个全局静态对象 demoInit,该对象会随着本源码文件中全局变量的创建和销毁调用其构造和析构方法,从而可以对全局变量 demo 生命周期进行管理:demo 一定在第一个 demoInit 对象创建时创建,在最后一个 demoInit 对象销毁时销毁,解决了全局对象的销毁及销毁顺序问题。