zoukankan      html  css  js  c++  java
  • 单例模式-C++

    单例模式(Singleton)

    --本文内容部分引自《大话设计模式 Chapter21》

    一.概念:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

      通常我们可以让一个全局变量使一个对象被访问,但它不能阻止你实例化多个对象,一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。

    二.结构

    单例模式因为Singleton类封装它的唯一实例,这样它可以严格的控制客户怎样访问它及何时访问它,简单来说就是对唯一实例的受控访问。

    单例类有状态,虽然实例唯一,却可以有子类来继承。

    特点:

    1、构造函数私有,防止外部实例化。这是第一点要求

    2、唯一实例句柄声明为static,这就是所谓唯一

    三.单线程模式:

     1     class CSingleton
     2     {
     3     public:
     4         static CSingleton *GetInstance()
     5         {
     6             if (NULL != m_Instance)
     7             {
     8                 m_Instace = new CSingleton();
     9             }
    10         }
    11         
    12     private:
    13         CSingleton();
    14 
    15     private:
    16         static CSingleton * m_Instance;
    17     };
    18     //此处初始化
    19     CSingleton* CSingleton::m_Instace = NULL;

    这里相应有一些可以提升的地方,比如实际实例类型不定的情况下,这里可以改为使用模板,类型待编译时刻再定;仅仅私有构造,还有其他方式会导致实例化,如拷贝构造。

     1     template <typename T>
     2     class CSingleton
     3     {
     4     public:
     5         static T *GetInstance()
     6         {
     7             if (NULL != m_Instance)
     8             {
     9                 m_Instace = new T;
    10             }
    11         }
    12         
    13     private:
    14         CSingleton();
    15         CSingleton(const T&);
    16         void operator=(const T&);
    17 
    18     private:
    19         static T * m_Instance;
    20     };
    21 
    22     //此处初始化
    23     template <typename T>
    24     T* CSingleton<T>::m_m_Instance= NULL;

    四、多线程模式:

    首先,提到多线程,那就马上要考虑同步的问题了,说到底就是锁,具体锁怎么实现这里不赘叙。

     5         static T *GetInstance()
     6         {
     7             m_mutex.Lock();
     8             if (NULL != m_Instance)
     9             {
    10                 m_Instance = new T;
    11             }
    12             m_mutex.UnLock();
    13         }

    还有需要考虑一个会遇到的多线程情况下遇到的问题,那就是上面写法的锁的位置,当句柄为NULL时,同时有两个线程调用到了GetInstance入口,拿到时间片的线程进入if里面new出对象,结束后另一个线程进入后,依旧会再new一次。这种可能是存在的。

    为了应对这种低概率但又不能无视的情况,大神们给出了方案--双重锁定(Double-Check Locking).

    GetInstance函数修改如下:

     1         static T *GetInstance()
     2         {
     3             if (NULL != m_Instance)
     4             {
     5                 m_mutex.Lock();
     6                 if (NULL != m_Instance)
     7                 {
     8                     m_Instance = new T;
     9                 }
    10                 m_mutex.UnLock();
    11             }
    12         }

    五、总结

    1.以上所有代码实现都是所谓的懒汉式单例类,因为是在第一次被引用时才会将自己实例化。

    相对有饿汉模式,就是在以上代码初始化的地方直接写成

    1     template <typename T>
    2     T* CSingleton::m_Instance = new T;

    这种静态初始化的方式称为饿汉式单例类

    2.目前实际使用中,只在项目工程中的日志记录、配置文件操作、内存池等全局唯一实例上,使用起来还是很方便的。

  • 相关阅读:
    P2788 数学1(math1)- 加减算式
    数据库第三章-学习笔记
    字典序
    P1739 表达式括号匹配
    P3742 umi的函数
    P1765 手机
    P2192 HXY玩卡片
    全排函数c++ next_permutation()
    11.css定义下拉菜单
    10.php引用(&)详解及注意事项
  • 原文地址:https://www.cnblogs.com/TTaiAL/p/6061915.html
Copyright © 2011-2022 走看看