再谈单例模式

来源:互联网 发布:html5 淘汰桌面软件 编辑:程序博客网 时间:2024/05/29 12:26

之前写过一篇博客 《C++单例模式的模板基类》 http://blog.csdn.net/kentzhang_/article/details/48206821 

但是,最近才发现实际 上 static  T* Instance() 的实现是有一点bug 的,下面分析。


 static T *Instance()          {              if(NULL != m_Instance)              {                  return m_Instance;              }                m_Mutex.Lock();              if(NULL != m_Instance)              {                  m_Mutex.UnLock();                  return m_Instance;              }                m_Instance = new(std::nothrow) T();              m_Mutex.UnLock();              return m_Instance;          }  

这种实现在多线程环境下,可能会有bug ,原因就在 m_Instance = new (std::nothrow) T() 这行代码。

这句代码实际上分三步执行:

1、分配内存

2、调用构造函数,初始化内存空间

3、将内存地址赋值给单例指针

代码可转化为如下形式:

T*  p  =  newMemory(sizeof(T))

p->BaseSingleton::BaseSingleton()

m_Instance = p

编译器出于优化的目的,可能会将第一步和第三步合并,变成如下:

m_Instance  =  newMemory(sizeof(T))

m_Instance->BaseSingleton::BaseSingleton()

那么在执完第一行代码时,有可能会切换到其他线程,其他线程如果调用 Instance()函数,由于m_Insatnce已经赋值,将返回这个指针,但是

指针指向的内存并未初始化,所以会造成不可预知的错误。


在Boost库中,有一种很好的单例实现模式,我做了一点修改,就是引用改成指针。代码如下:

#ifndef BASESINGLETON_H#define BASESINGLETON_H/**  单例模式采用boost源码  由于boost单例返回的是引用,下面改成指针  */template<class T>class BaseSingleton{public:    BaseSingleton(){}private:    struct object_creator    {        // This constructor does nothing more than ensure that instance()        //  is called before main() begins, thus creating the static        //  T object before multithreading race issues can come up.        object_creator() { BaseSingleton<T>::Instance(); }        inline void do_nothing() const { }    };    static object_creator create_object;    //BaseSingleton();public:    typedef T object_type;    // If, at any point (in user code), BaseSingleton<T>::instance()    //  is called, then the following function is instantiated.    static object_type* Instance()    {        // This is the object that we return a reference to.        // It is guaranteed to be created before main() begins because of        //  the next line.        static object_type obj;        // The following line does nothing else than force the instantiation        //  of BaseSingleton<T>::create_object, whose constructor is        //  called before main() begins.        create_object.do_nothing();        return &obj;    }};template <class T>typename BaseSingleton<T>::object_creatorBaseSingleton<T>::create_object;#endif // BASESINGLETON_H

我之前实现的单例模式中,必须是第一次手动调用Instance()才生成单例对象,这样就引入了多线程的问题。

而Boost实现方式,在单例类中定义一个内嵌的静态的结构体,这个结构体生成时调用自己的构造函数,构造函数中执行Instance()函数,由于单例类内的静态的结构体生成时,是在main()执行之前,所以巧妙地绕开了多线程的问题。






0 0
原创粉丝点击