C++之单例模式

来源:互联网 发布:mac把图标放在桌面 编辑:程序博客网 时间:2024/06/05 07:22

C++之单例模式

单例模式也称为单件模式、单子模式,可能是使用最广泛的设计模式。其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。有很多地方需要这样的功能模块,如系统的日志输出,GUI应用必须是单鼠标,MODEM的联接需要一条且只需要一条电话线,操作系统只能有一个窗口管理器,一台PC连一个键盘。

方法一:饿汉模式,即指单例实例在程序运行时被立即执行初始化

class Singleton  {public:    static Singleton * Instance() {        return &m_pInstance;    }private:    Singleton ();              // ctor is hidden    Singleton (Singleton  const&);    // copy ctor is hidden    static Singleton  m_pInstance;};// in Singleton.cpp we have to addSingleton  Singleton ::m_pInstance;

此种方法不足:如果有两个单例模式的类 ASingleton 和 BSingleton, 某天你想在 BSingleton 的构造函数中使用 ASingleton 实例, 这就出问题了. 因为 BSingleton m_pInstance 静态对象可能先 ASingleton 一步调用初始化构造函数, 结果 ASingleton::Instance() 返回的就是一个未初始化的内存区域, 程序还没跑就直接崩掉.

方法二:懒汉模式,即单例实例只在第一次被使用时进行初始化

class Singleton {public:    static Singleton* Instance() {        if (!m_pInstance)            m_pInstance = new Singleton;        return m_pInstance;    }private:    Singleton();        // ctor is hidden    Singleton(Singleton const&);    // copy ctor is hidden    static Singleton* m_pInstance;};// in .cpp we have to addSingleton* Singleton::m_pInstance = NULL;

Instance() 只在第一次被调用时为 m_pInstance 分配内存并初始化. 嗯, 看上去所有的问题都解决了, 初始化顺序有保证, 多态也没问题.

不过细心的你可能已经发现了一个问题, 程序退出时, 析构函数没被执行. 这在某些设计不可靠的系统上会导致资源泄漏, 比如文件句柄, socket 连接, 内存等等. 幸好 Linux / Windows 2000/XP 等常用系统都能在程序退出时自动释放占用的系统资源. 不过这仍然可能是个隐患,有些系统是不会自动释放的.

对于这个问题, 比较土的解决方法是, 给每个 Singleton 类添加一个 destructor() 方法,采用RAII方法:

class CSingleton:{  public:      static CSingleton * GetInstance()  private:      CSingleton(){};      static CSingleton * m_pInstance;      class CGarbo // 它的唯一工作就是在析构函数中删除CSingleton的实例      {    public:        ~CGarbo()        {              if (CSingleton::m_pInstance)                delete CSingleton::m_pInstance;       CSingleton::m_pInstance=-=NULL;        }    };    static CGarbo Garbo; // 定义一个静态成员,在程序结束时,系统会调用它的析构函数};

然后在程序退出时确保调用了每个 Singleton 类的 destructor() 方法, 这么做虽然可靠, 但却很是繁琐。

考虑到线程安全、异常安全,方法二可以做以下扩展:

class Lock  {  private:             CCriticalSection m_cs;  public:      Lock(CCriticalSection  cs) : m_cs(cs)   {          m_cs.Lock();      }      ~Lock()    {          m_cs.Unlock();      }  };  //RAII模式class Singleton  {  private:      Singleton();      Singleton(const Singleton &);      Singleton& operator = (const Singleton &);      class CGarbo   {       public:          ~CGarbo()        {              if (CSingleton::m_pInstance){                 delete CSingleton::m_pInstance;                 CSingleton::m_pInstance=-=NULL;            }     };    static CGarbo Garbo; // 定义一个静态成员,在程序结束时,系统会调用它的析构函数 public:      static Singleton *Instantialize();      static Singleton *pInstance;      static CCriticalSection cs;  };  Singleton* Singleton::pInstance = 0;Singleton* Singleton::Instantialize()  {      if(pInstance == NULL)      {   //double check          Lock lock(cs);                   //用lock实现线程安全,用资源管理类,实现异常安全          //使用资源管理类,在抛出异常的时候,资源管理类对象会被析构,析构总    是发生的无论是因为异常抛出还是语句块结束。          if(pInstance == NULL)                    pInstance = new Singleton();              }      return pInstance;  }

方法三、最优实现写法

class Singleton {public:    static Singleton& Instance() {        static Singleton theSingleton;        return theSingleton;    }   private:    Singleton();                            // ctor hidden    Singleton(Singleton const&);            // copy ctor hidden    Singleton& operator=(Singleton const&); // assign op. hidden    ~Singleton();                           // dtor hidden};

在 Instance() 函数内定义局部静态变量的好处是, theSingleton的构造函数只会在第一次调用 Instance() 时被初始化, 达到了和 “堆栈版” 相同的动态初始化效果, 保证了成员变量和 Singleton 本身的初始化顺序.

它还有一个潜在的安全措施, Instance() 返回的是对局部静态变量的引用, 如果返回的是指针, Instance() 的调用者很可能会误认为他要检查指针的有效性, 并负责销毁. 构造函数和拷贝构造函数也私有化了, 这样类的使用者不能自行实例化.

另外, 多个不同的 Singleton 实例的析构顺序与构造顺序相反.

同样可以用Lock保证线程安全。

此处的单例模式特点如下:
1. 它有一个指唯一实例的静态指针m_pInstance,并且是私有的。
2. 它有一个公有的函数,可以获取这个唯一的实例,并在需要的时候创建该实例。
3. 它的构造函数是私有的,这样就不能从别处创建该类的实例。

参考链接:

  1. http://stackoverflow.com/questions/86582/singleton-how-should-it-be-used

  2. http://blog.csdn.net/taiyang1987912/article/details/43202271

  3. http://www.cnblogs.com/wxxweb/archive/2011/04/15/2017088.html

  4. http://www.programlife.net/cpp-singleton-memory-retrieve.html

  5. http://stackoverflow.com/questions/270947/can-any-one-provide-me-a-sample-of-singleton-in-c/271104#271104

  6. http://stackoverflow.com/questions/1008019/c-singleton-design-pattern/1008289#1008289

0 0
原创粉丝点击