假设我在静态库中有一个单例类 S,它可以与其他动态库 D1 D2 D3 链接,
因此,据我了解,类 S 在每个 D1、D2 和 D3 中都会有一个单独的实例,即使它不是单例(如全局),这也是正确的
有什么办法可以防止S类的多副本吗?
我无法将单例 S 放入另一个动态库中。
Executable
/ | \ \
D1 D2 D3 D4
| | |
S S S
编辑:
单例 S 位于单独的静态库中,分别与 D1 D2 D3... 链接。
单例是在堆中分配的,只有指针是静态的
static s::instance()
{
static smart_ptr<S> ptr = NULL;
if(ptr == NULL) ptr = new S;
return ptr;
}
Edit2:
我做了一个简单的测试用例来检查一下
这是我为了检查而制作的示例 makefile(用 .so 替换 .dll),我在 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 的目标文件,动态加载器也应该足够聪明,能够确定它们对应于相同的符号,并在整个应用程序中一致地使用相同的地址。
In short, if your system is not broken has a true dynamic loader, there is no problem here
根据您的编辑,我确认上面的内容是在一个美好的世界中应该有的方式,也是在类 Unix 系统中的方式。你说它在 Ubuntu 上工作,我可以确认在 FreeBSD 上也同样工作。
但不幸的是,在 Windows 上情况有所不同。你没有像这样的真正的动态加载器ld.so
但您只需要 DLL 中导出函数或数据的地址。因此,每个 DLL 将使用自己的单例副本,因为每个 DLL 将包含自己的代码副本并使用它,因为没有全局链接阶段来合并它。
更糟糕的是,我无法想象任何简单的解决方法:静态链接和动态链接具有不同的行为句号。这意味着,只要您在 Windows 上使用动态链接,单例或可从至少两个不同 DLL 访问的任何共享数据都必须驻留在一个位置,即 DLL。
TL/DR:如果你的系统有一个真正的动态加载器(Unix之类的有),你不必担心静态或动态链接,加载器(ld.so
)会关心它。在 Windows 上,它没有动态加载程序,但有一个运行时LoadLibrary
API调用时,任何共享数据必须驻留在一个且仅一个模块中。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)