C++单列模式跨DLL是不是会出问题?

2021-12-14 15:22发布

嘿嘿嘿,这个坑我在工作中发现很多同事都踩进去过,而且半天出不来,怎么调怎么都不对(看戏(我没有))

先回答“C++单例模式跨DLL是不是就是会出问题”这个问题,后面再解释。以后同事再问我也可以拿这个回答直接给他看,省得费口舌了。

C++单例模式跨DLL是不是就是会出问题——如果没有使用对就会有问题,或者说你只是看网上的各种初学者博客上一顿互抄的文章,简单地在类里使用了一下static变量作为单例,并期望这个单例能跨动态库,那就出问题了。比如一堆博客中都会给出的这段代码就是有问题的:

tatic变量是单个编译单元的静态变量,内存将被分配于当前的编译单元中,此时如果你编可执行文件的代码和编动态库的代码都包含了上述的单例头文件,那么这个“单例”将会出现两个实例,一个实例的内存在可执行文件中,一个实例的内存在动态链接库中,在运行存在于可执行文件中的代码段时,使用的是可执行文件中的那一份“单例”,而在运行存在于动态链接库中的代码段时,使用的则是动态链接库中的那一份“单例”,这其实本质就是所谓的动态链接库间的内存隔离导致的问题。

解决这个问题有两条路:

1.设计代码时选好单例的内存该放在哪,然后通过导入导出解决(MSVC上导入导出使用__declspec(dllimport)和__declspec(dllexport),类比extern变量)。比如单例打算放在动态链接库A中,那就在生成动态库A的地方的这个static变量导出,其他动态链接库或可执行文件使用的地方导入。

2.搞个统一的地方大家的单例共同注册到一起,用的时候拿出来。

我采用的解决方式是第2种,大家共同把单例注册到一个独立的动态库singleton_manager中,使用时只需要继承GlobalSingleton

即可(需要注意我实现的这个单例的singleton_manager只记录了指针,如果有热卸载动态库的需求,那么不适用)