Igo*_*Oks 1 c++ dll singleton static raii
我们有3个不同的库,每个库由不同的开发人员开发,每个库(大概)设计得很好.但是,由于某些库正在使用RAII而某些库没有,并且某些库是动态加载的,而其他库则不是 - 它不起作用.
每个开发人员都说他正在做的事情是正确的,并且仅针对这种情况进行方法改变(例如在B中创建RAII单例)将解决问题,但看起来就像一个丑陋的补丁.
你会如何建议解决这个问题?
请查看代码以了解问题:
我的代码:
static A* Singleton::GetA()
{
static A* pA = NULL;
if (pA == NULL)
{
pA = CreateA();
}
return pA;
}
Singleton::~Singleton() // <-- static object's destructor,
// executed at the unloading of My Dll.
{
if (pA != NULL)
{
DestroyA();
pA = NULL;
}
}
Run Code Online (Sandbox Code Playgroud)
"A"代码(在另一个Dll中,与我的Dll静态链接):
A* CreateA()
{
// Load B Dll library dynamically
// do all other initializations and return A*
}
void DestroyA()
{
DestroyB();
}
Run Code Online (Sandbox Code Playgroud)
"B"代码(在另一个Dll中,从A动态加载):
static SomeIfc* pSomeIfc;
void DestroyB()
{
if (pSomeIfc != NULL)
{
delete pSomeIfc; // <-- crashes because the Dll B was unloaded already,
// since it was loaded dynamically, so it is unloaded
// before the static Dlls are unloaded.
pSomeIfc = NULL;
}
}
Run Code Online (Sandbox Code Playgroud)
jal*_*alf 11
我的回答与人们每次关于单身人士的回答是一样的:不要去做!
在卸载某些库之后,您的单例会导致析构函数被调用太晚.如果你删除了"静态"并使它成为一个常规对象,在更严格的范围内实例化,它将在任何库被卸载之前被销毁,并且一切都应该再次工作.
只是不要使用单身人士.
首先,在给出的示例中,我没有看到自从您在其中声明为静态局部变量后如何Singleton::~Singleton()访问.pApASingleton::getA()
然后你解释说"B"库是动态加载的A* Create();.它在哪里卸载呢?为什么void DestroyA()在调用之前没有卸载"B"库DestroyB()?
你怎么称呼"静态链接DLL"?
最后,我不想苛刻,但肯定有更好的设计将单身人士放在各处:换句话说,你真的需要管理"A"生命周期的对象是单身吗?您可以CreateA()在应用程序开始时调用并依赖于atexit进行DestroyA()调用.
编辑:由于您依靠操作系统卸载"B"库,为什么不DestroyB()从DestroyA()实现中删除调用.然后DestroyB()在"B"库使用RAII卸载时进行调用(或者甚至是OS特定的机制,例如DllMain在Windows下调用它并__attribute__((destructor))在Linux或Mac下标记它).
编辑2:显然,从你的评论来看,你的节目有很多单身人士.如果他们是静态单身人士(称为迈耶斯单身人士),并且他们彼此依赖,那么它迟早会破裂.控制破坏的顺序(因此单身生命周期)需要一些工作,参见Alexandrescu的书或@Martin在评论中给出的链接.
参考文献(有点相关,值得一读)