Meyers Singleton是否适用于具有动态库的场景? 即一个库定义单例,其他库使用它,每个库都在自己的编译单元中? (我认为没关系,但具体的架构是OS X上的框架应用程序)
我正在使用vanilla Meyers Singleton模式:以下Instance()
方法在实用程序类的头文件中内联定义(在动态库中定义):
static Logger& Instance()
{
static Logger singletonInstance;
return singletonInstance;
}
复制构造函数和operator=
被声明为私有而未实现,所以我们应该很好,对吧?
现在,如果我从主应用程序链接定义单例的库,我可以看到构造函数被称为多次 ..具有this
的不同地址以及我期望的所有奇怪当没有实际的单身人士但是有多个班级的实例时。
所以我想知道动态库方法是否搞砸了Meyers单例或每个编译单元 - 库,主应用程序 - 包括单例的标题(有效声明和定义实例()方法)将获得“它自己的单例实例”?
真的不太清楚我的观察结果如何,所以任何提示都非常赞赏!
答案 0 :(得分:9)
您需要在标头中声明 Instance
,然后在动态库中定义(可能与Logger
相同定义于)。你需要放弃static
。如果您使用visibility tools,则需要确保Instance
具有默认可见性。
根据您的描述,听起来您已经在标题中定义了此功能。这将为包含标题的每个人提供他们自己的Instance
私人定义,从而为static Logger
中的Instance
提供他们自己的私人定义。
你可以声明Instance
inline
,这会给你所期望的所有语义(与在标题中声明和在dylib中定义相同)。但我的建议是只做内联来确认我告诉你的是正确的(这很容易),然后勾勒出一个dylib(并再次确认)。
概述后,您的设计应该可以正常工作。
话虽如此,它只能保证在C ++ 11中运行。也就是说,本地静态在C ++ 98/03中不是线程安全的,但在C ++ 11及更高版本中。但是,在OS X上,即使在C ++ 03语言模式下,它们也是线程安全的扩展名。
另一个警告:如果您访问atexit链中的Instance()
(或全局对象的析构函数中),则可能会在破坏静态本地singletonInstance
之后访问您的访问权限。在Instance()
内,导致未定义的行为。如果您没有使用atexit()
注册内容,并且您的全局析构函数未调用Instance()
,那么您就是安全的。否则你不是。如果您不安全,可以故意泄漏它:
Logger& Instance()
{
static Logger* singletonInstance = new Logger;
return *singletonInstance;
}
这可能会导致一些内存泄漏检查程序报告误报(或者根据您的观点,它们可能是真正的正面),这很令人恼火。