oku*_*ane 30 c++ singleton design-patterns
我已经看到了Singleton模式的实现,其中实例变量在GetInstance方法中被声明为静态变量.像这样:
SomeBaseClass &SomeClass::GetInstance()
{
static SomeClass instance;
return instance;
}
Run Code Online (Sandbox Code Playgroud)
我认为这种方法有以下积极方面:
这种方法的不利方面是什么(除了这不是非常OOP-ish)?这是线程安全的吗?
Mar*_*ork 38
在C++ 11中,它是线程安全的:
§6.7[stmt.dcl] p4如果控制在初始化变量时同时进入声明,则并发执行应等待初始化完成.
在C++ 03中:
一个问题是,如果你有两个单身人士,他们会在施工和破坏期间互相尝试使用.
阅读: 查找C++静态初始化顺序问题
这个问题的一个变种是如果从全局变量的析构函数访问单例.在这种情况下,单例肯定已被破坏,但get方法仍将返回对被破坏对象的引用.
有办法解决这个问题,但它们很混乱,不值得做.只是不要从全局变量的析构函数中访问单例.
一个更安全的定义,但丑陋:
我相信你可以添加一些适当的宏来整理它
SomeBaseClass &SomeClass::GetInstance()
{
#ifdef _WIN32
Start Critical Section Here
#elif defined(__GNUC__) && (__GNUC__ > 3)
// You are OK
#else
#error Add Critical Section for your platform
#endif
static SomeClass instance;
#ifdef _WIN32
END Critical Section Here
#endif
return instance;
}
Run Code Online (Sandbox Code Playgroud)
如图所示,它不是线程安全的.C++语言在线程上是静默的,因此您没有语言的固有保证.您必须使用平台同步原语(例如Win32 :: EnterCriticalSection())来保护访问.
你的特定方法是有问题的b/c编译器将插入一些(非线程安全的)代码来初始化instance第一次调用时的静态,很可能它将在函数体开始执行之前(因此在调用任何同步之前). )
使用全局/静态成员指针SomeClass然后在同步块内初始化将证明实现的问题较少.
#include <boost/shared_ptr.hpp>
namespace
{
//Could be implemented as private member of SomeClass instead..
boost::shared_ptr<SomeClass> g_instance;
}
SomeBaseClass &SomeClass::GetInstance()
{
//Synchronize me e.g. ::EnterCriticalSection()
if(g_instance == NULL)
g_instance = boost::shared_ptr<SomeClass>(new SomeClass());
//Unsynchronize me e.g. :::LeaveCriticalSection();
return *g_instance;
}
Run Code Online (Sandbox Code Playgroud)
我没有编译这个,所以它仅用于说明目的.它还依赖于boost库来获得与原始示例相同的生命周期(或那里).您还可以使用std :: tr1(C++ 0x).