静态库中的Singleton类

tej*_*jas 7 c++ singleton design-patterns static-libraries dynamic-library

假设我在静态库中有一个单例类S,这可以与其他动态库D1 D2 D3链接,

所以根据我的理解,类S将在每个D1,D2和D3中有一个单独的实例,即使它不是单例(如全局)也是如此

有没有办法防止S类的多个副本?我不能将单例S放在另一个动态库中.

                 Executable
                /   |   \   \
              D1    D2  D3  D4 
               |    |   |
               S    S   S
Run Code Online (Sandbox Code Playgroud)

编辑:单例S在一个单独的静态库中,分别与D1 D2 D3 ...链接.
单例在堆中分配,只有指针是静态的

static s::instance()
{
    static smart_ptr<S> ptr = NULL;
    if(ptr == NULL) ptr = new S;
    return ptr;
}
Run Code Online (Sandbox Code Playgroud)

EDIT2:

我做了一个简单的测试用例来检查出来这是一个示例makefile(用.so替换.d)我做了检查,我在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
Run Code Online (Sandbox Code Playgroud)

Ser*_*sta 9

如果您的动态链接器没有损坏,那么您应该没有任何问题.即使每个动态库实际上都包含来自静态库S的目标文件,动态加载器也应该足够聪明,以确定它们对应于相同的符号,并在整个应用程序中始终使用相同的地址.

总之,如果你的系统 没有打破 有一个真正的动态加载器,这里没有问题


根据您的编辑,我确认上面是它应该在一个美好的世界中的方式以及它在类Unix系统中的方式.你说它适用于Ubuntu,我可以确认它在FreeBSD上是一样的.

但在Windows上,不幸的是它不同.您没有真正的动态加载器,ld.so但您只需要导出函数的地址或DLL中的数据.因此,每个DLL都将使用自己的单例副本,因为每个DLL都包含自己的代码副本并使用它,因为没有全局链接阶段来合并它.

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

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