静态库中的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都将包含它自己的代码副本,并使用它,因为没有全局链接阶段来合并它。

更糟糕的是,我无法想象任何简单的解决方法:静态链接和动态链接具有完全不同的行为。这意味着只要在Windows上使用动态链接,可以从至少两个不同的DLL访问的单例或任何共享数据必须驻留在单个位置,即DLL。

TL/DR:如果您的系统有一个真正的动态加载器(Unix,如HAVE),您不必担心静态或动态链接,加载器(ld.so)会关心它。在Windows上,没有动态加载器,但有一个运行时LoadLibraryAPI调用,任何共享数据都必须驻留在且只能驻留在一个模块中。

相关文章