就我所理解的名称空间范围而言,静态变量应该在每个编译单元中有一个副本。因此,如果我有这样的头文件:
class BadLad {
public:
BadLad();
~BadLad();
};
static std::unique_ptr<int> sCount;
static BadLad sBadLad;和badlad.cpp
#include "badlad.h"
BadLad::BadLad() {
if (!sCount) {
sCount.reset(new int(1));
std::cout<<"BadLad, reset count, "<<*sCount<<std::endl;
}
else {
++*sCount;
std::cout<<"BadLad, "<<*sCount<<std::endl;
}
}
BadLad::~BadLad() {
if (sCount && --*sCount == 0) {
std::cout<<"~BadLad, delete "<<*sCount<<std::endl;
delete(sCount.release());
}
else {
std::cout<<"~BadLad, "<<*sCount<<std::endl;
}
}我希望sCount和sBadLad在每个包含badlad.h的cpp文件中是唯一的。
然而,在下面的实验中,我发现情况并非如此:
libBadLad.so。libPlugin.so,它链接libBadLad.so,只有plugin.cpp包含badlad.h,所以我希望libPlugin.so中有一个sCount副本。sCount的副本。主程序如下所示:
#include <dlfcn.h>
int main() {
void* dll1 = dlopen("./libplugin.so", RTLD_LAZY);
dlclose(dll1);
void* dll2 = dlopen("./libplugin.so", RTLD_LAZY);
dlclose(dll2);
return 0;
}在执行主程序时,我可以看到首先创建了sCount变量,并在调用main之前将其设置为1,这是预期的。但是,在第一个dlopen被调用之后,sCount被增加到2,然后当dlclose被调用时减少到1。同样的情况发生在第二个dlopen/dlclose上。
所以我的问题是,为什么只有一个副本的sCount?为什么链接器不将副本分开(我认为这是大多数人所期望的)?如果我直接将libPlugin.so链接到main,而不是dlopen,它的行为也是一样的。
我正在使用clang-4 (clang-900.0.39.2)在macOS上运行这个程序。
编辑:请参阅这个回购的完整源代码。
发布于 2018-02-07 08:03:53
(迭代2)
在你的情况下发生的事情是非常有趣和非常不幸的。让我们一步一步地分析。
libBadLad.so链接的。因此,在程序启动时加载此共享库。静态对象的构造函数在main之前执行。libplugin.so。然后加载这个共享库,并执行静态对象的构造函数。libBadLad.so相关联的libplugin.so呢?由于进程已经包含了libBadLad.so的映像,所以这个共享库不会在第二次加载时加载。libplugin.so也可以完全不链接到它。libplugin.so的静态对象。其中有两个,sCount和sBadLad。两者都是按顺序建造的。sBadLad有一个用户定义的非内联构造函数.它不是在libplugin.so中定义的,所以它是根据已经加载的libBadLad.so解析的,后者定义了这个符号。BadLad::BadLad是从libBadLad.so调用的。sCount。这将从libBadLad.so__解析为sCount,而不是从libplugin.so解析为sCount,因为函数本身位于libBadLad.so中。这已经初始化,并指向值为1的int。sCount从libplugin.so静静地坐着,被初始化为nullptr。这个故事的寓意是?静态变量是邪恶的。避免。
注意,C++标准对此没有什么可说的,因为它不处理动态加载。
然而,一种类似的效果可以在没有任何运动厌恶的情况下再现。
// foo.cpp
#include "badlad.h"
// bar.cpp
#include "badlad.h"
int main () {}构建和测试:
# > g++ -o test foo.cpp bar.cpp badlad.cpp
./test
BadLad, reset count to, 1
BadLad, 2
BadLad, 3
~BadLad, 2
Segmentation fault为什么分割错误?这是我们以前的静态初始化命令失败了。故事的寓意?静态变量是邪恶的。
https://stackoverflow.com/questions/48629063
复制相似问题