静态库中的Singleton类
假设我在静态库中有一个单例类S,它可以与其他动态库d1、d2、d3链接,
因此,据我所知,类S在每个d1、d2和d3中都有一个单独的实例,即使它不是单例(如全局)也是如此
有没有办法防止S类的多个副本? 我无法将单例%S放入其他动态库中。
Executable
/ |
D1 D2 D3 D4
| | |
S S S
编辑:
单例S位于一个单独的静态库中,该库链接到D1D2D3...分开。
单例在堆中分配,只有指针是静态的
static s::instance()
{
static smart_ptr<S> ptr = NULL;
if(ptr == NULL) ptr = new S;
return ptr;
}
编辑2:
我做了一个简单的测试用例来检查 这是我制作的一个样例Makefile(将.dll替换为.so),我在Ubuntu和Cygwin上检查了它,两者都是g++编译器,行为不同。Cygwin创建了%2个不同的对象,但ubuntu创建了%1个对象
all: dynamic1 dynamic2 main
static: static.cpp
g++ -c -fPIC static.cpp -o obj/static.o
ar rvs lib/static.a obj/static.o
dynamic1: static dynamic1.cpp
g++ -fPIC -shared dynamic1.cpp lib/static.a -o lib/libdynamic1.dll
dynamic2: static dynamic2.cpp
g++ -fPIC -shared dynamic2.cpp lib/static.a -o lib/libdynamic2.dll
main: dynamic1 dynamic2 main.cpp
g++ --std=c++11 main.cpp -ldynamic1 -ldynamic2 -o lib/main -L./lib
解决方案
如果您的动态链接器没有损坏,应该不会有任何问题。即使每个动态库实际上都包含来自静态库S的目标文件,动态加载器也应该足够聪明,以确定它们对应于相同的符号,并在整个应用程序中始终使用相同的地址。
简而言之,如果您的系统没有损坏有一个真正的动态加载程序,这里就没有问题
根据您的编辑,我确认上面就是它在美好世界中应该是的方式,以及它在类Unix系统中的方式。你说它可以在Ubuntu上运行,我可以肯定它在FreeBSD上也可以运行。
但不幸的是,在Windows上却有所不同。您没有像ld.so
这样的真正的动态加载器,但您只需要从DLL中导出函数或数据的地址。因此,每个DLL将使用它自己的单例副本,因为每个DLL都将包含它自己的代码副本,并使用它,因为没有全局链接阶段来合并它。
TL/DR:如果您的系统有一个真正的动态加载器(Unix,如HAVE),您不必担心静态或动态链接,加载器(ld.so
)会关心它。在Windows上,没有动态加载器,但有一个运行时LoadLibrary
API调用,任何共享数据都必须驻留在且只能驻留在一个模块中。
相关文章