Meyers Singleton 是否适用于有动态库的场景?
IE。一个定义单例的库,其他人使用它,每个都在自己的编译单元中?
(我想这无关紧要,但具体架构是 OS X 上带有框架的应用程序)
我正在使用 Vanilla Meyers Singleton 模式:以下 Instance()
方法是在实用程序类的头文件中内联定义的(在动态库中定义):
static Logger& Instance()
{
static Logger singletonInstance;
return singletonInstance;
}
复制构造函数和 operator=
被声明为私有(private)且未实现,所以我们应该很好,对吧?
现在,如果我从主应用程序链接定义单例的库,我可以看到构造函数被调用多次.. this
的地址不同以及所有奇怪的地方我希望当没有实际的单例但类的多个实例时。
所以我想知道动态库方法是否搞砸了 Meyers 单例,或者每个编译单元 - 库,主应用程序 - 是否包含单例的 header (有效地声明和定义实例() 方法) 会得到“它自己的单例实例”吗?
真的不太确定我的观察结果如何,所以非常感谢任何提示!
最佳答案
您需要在 header 中声明 Instance
,然后在动态库中定义它(大概是 Logger
定义在)。您需要删除 static
。如果您使用 visibility tools,您需要确保 Instance
具有默认可见性.
根据您的描述,听起来您已经在 header 中定义了这个函数。这将为包含 header 的每个人提供他们自己的 Instance
私有(private)定义,因此他们自己对 Instance
中的 static Logger
的私有(private)定义。
您可以声明 Instance
inline
,这将为所有内容提供您期望的语义(与在 header 中声明和在 dylib 中定义相同)。但我的建议是只做内联以确认我告诉你的是正确的(这很容易),然后将大纲放入动态库中(并再次确认)。
勾勒出轮廓后,您的设计应该可以正常工作。
也就是说,它只能保证在 C++11 中工作。也就是说,局部静态在 C++98/03 中不是线程安全的,但在 C++11 及更高版本中是线程安全的。但是,在 OS X 上,作为扩展,即使在 C++03 语言模式下,它们也是线程安全的。
另一个注意事项:如果您在 atexit 链(或在全局对象的析构函数中)访问 Instance()
,您的访问可能发生在静态本地对象的析构之后Instance()
中的 singletonInstance
,导致未定义的行为。如果您不使用 atexit()
进行注册,并且您的全局析构函数不调用 Instance()
,那么您就是安全的。否则你不是。如果你不安全,你可以故意泄露它:
Logger& Instance()
{
static Logger* singletonInstance = new Logger;
return *singletonInstance;
}
这可能会导致一些内存泄漏检查器报告误报(或者根据您的观点,它们可能是真报),这很烦人。
关于c++ - Meyers 单例和动态库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21442758/