迈尔斯单身人士和动态图书馆

ATV*_*ATV 4 c++ macos singleton design-patterns c++11

Meyers Singleton是否适用于具有动态库的场景?
即一个库定义单例,其他人使用它,每个库都在自己的编译单元中?
(我想这没关系,但具体的架构是OS X上的框架应用程序)

我正在使用vanilla Meyers Singleton模式:Instance()在实用程序类的头文件中内联定义了以下方法(在动态库中定义):

    static Logger&  Instance()
              {
                 static Logger singletonInstance;
                 return singletonInstance;
              }
Run Code Online (Sandbox Code Playgroud)

复制构造函数并被operator=声明为私有而未实现,所以我们应该很好,对吧?

现在,如果我链接从主应用程序定义单例的库,我可以看到构造函数被多次调用..具有不同的地址this和所有奇怪的我没有实际单例但是类的多个实例.

所以我想知道动态库方法是否搞砸了Meyers单例,或者每个编译单元 - 库,主应用程序 - 包含单例的标题(有效地声明和定义 Instance()方法)将得到" 它自己的单例"实例 "?

真的不太清楚我的观察结果如何,所以任何提示都非常赞赏!

How*_*ant 9

您需要在标头中声明 Instance,然后在动态库中定义它(可能与Logger定义的相同).你需要放弃static.Instance如果您使用可见性工具,则需要确保具有默认可见.

根据您的描述,听起来您已经在标题中定义了此功能.这将为每个包含头部的人提供他们自己的私有定义Instance,从而为他们自己的static Logger内部私有定义Instance.

你可以声明Instance inline,这会给你所期望的所有语义(与在标题中声明和在dylib中定义相同).但我的建议是只做内联来确认我告诉你的是正确的(这很容易),然后勾勒出一个dylib(并再次确认).

概述后,您的设计应该可以正常工作.

话虽这么说,它只能保证在C++ 11中工作.也就是说,本地静态在C++ 98/03中不是线程安全的,但在C++ 11及更高版本中.但是,在OS X上,即使在C++ 03语言模式下,它们也是线程安全的扩展.

另一个警告:如果您Instance()在atexit链中(或在全局对象的析构函数中)访问,则可能会在破坏静态本地singletonInstance内部后发生访问Instance(),从而导致未定义的行为.如果你没有注册atexit(),如果你的全球析构函数没有打电话Instance(),你就是安全的.否则你不是.如果您不安全,可以故意泄漏它:

Logger&  Instance()
{
   static Logger* singletonInstance = new Logger;
   return *singletonInstance;
}
Run Code Online (Sandbox Code Playgroud)

这可能会导致一些内存泄漏检查程序报告误报(或者根据您的观点,它们可能是真正的正面),这令人恼火.