<dl id="opymh"></dl>

<div id="opymh"></div>
      <div id="opymh"><tr id="opymh"></tr></div>

        <em id="opymh"><ins id="opymh"><mark id="opymh"></mark></ins></em><sup id="opymh"><menu id="opymh"></menu></sup>

        <em id="opymh"></em>

        <em id="opymh"><ol id="opymh"></ol></em>

              频道栏目
              首页 > 程序开发 > 软件开发 > C++ > 正文
              C++的单例模式的几种实现方式解析
              2018-07-27 13:51:52         来源_____________________________________simanstar____  
              收藏   我要投稿

              单例模式有两种实现模式

              1懒汉模式 就是说当你第一次使用时才创建一个唯一的实例对象从而实现延迟加载的效果

              2饿汉模式 就是说不管你将来用不用程序启动时就创建一个唯一的实例对象

              所以从实现手法上看懒汉模式是在第一次使用单例对象时才完成初始化工作因为此时可能存在多线程竞态环境如不加锁限制会导致重复构造或构造不完全问题

              饿汉模式则是利用外部变量在进入程序入口函数之前就完成单例对象的初始化工作此时是单线程所以不会存在多线程的竞态环境故而无需加锁

              以下是典型的几种实现

              一 懒汉模式标准的 ”双检锁“ + ”自动回收“ 实现

              class Singleton
              {
              public:
                  static Singleton* GetInstance()
                  {
                      if (m_pInstance == NULL )
                      {
                          Lock(); // 加锁
                          if (m_pInstance == NULL )
                          {
                              m_pInstance = new Singleton ();
                          }
                          UnLock(); // 解锁
                      }
                      return m_pInstance;
                  }
              
                  // 实现一个内嵌垃圾回收类    
                  class CGarbo 
                  {
                  public:
                      ~CGarbo()
                      {
                          if(Singleton::m_pInstance) 
                              delete Singleton::m_pInstance;
                      }
                  };
              
                  static CGarbo Garbo; // 定义一个静态成员变量程序结束时系统会自动调?#30431;?#30340;析构函数从而释放单例对象
              
              private:
                  Singleton(){};
                  Singleton(Singleton const&); 
                  Singleton& operator=(Singleton const&); 
              
                  static Singleton* m_pInstance;
              };
              
              Singleton* Singleton::m_pInstance = NULL;
              Singleton::CGarbo Garbo;

              二静态局部变量的懒汉模式 而不是new在堆上创建对象避免自己回收资源

              这里仍然要注意的是局部变量初始化的线程安全性问题在C++0X?#38498;?#35201;求编译器保证静态变量初始化的线程安全性可以不加锁但C++ 0X以前仍需要加锁

              class Singleton
              {
              public:
                  static Singleton* GetInstance()
                  {
                      Lock(); // not needed after C++0x 
                      static Singleton instance;  
                      UnLock(); // not needed after C++0x 
              
                      return &instance;
                  }
              
              private:
                  Singleton() {};
                  Singleton(const Singleton &);
                  Singleton & operator = (const Singleton &);
              };

              在懒汉模式里如果大量并发线程获取单例对象在进行频繁加锁解锁操作时必然导致效?#23454;?#19979;

              三饿汉模式基础版本

              因为程序一开始就完成了单例对象的初始化所?#38498;?#32493;不再需要考虑多线程安全性问题就可以避免懒汉模式里频繁加锁解锁带来的开销

              class Singleton
              {
              public:
              
                  static Singleton* GetInstance()
                  {
                      return &m_instance;
                  }
              
              private:
                  Singleton(){};
                  Singleton(Singleton const&); 
                  Singleton& operator=(Singleton const&); 
              
                  static Singleton m_instance;
              };
              
              Singleton Singleton::m_instance;  // 在程序入口之前就完成单例对象的初始化

              虽然这种实现在一定程度下能?#24049;?#24037;作但是在某些情况下会带?#27425;?#39064; --- 就是在C++中 ”非局部静态对象“ 的 ”初始化“ 顺序 的 ”不确定性“ 参见Effective c++ 条款47

              考虑 如果有两个这样的单例类将分别生成单例对象A, 单例对象B. 它们分别定义在不同的编译单元cpp中 而A的初始化依赖于B 即A的构造函数中要调用B::GetInstance() 而此时B::m_instance 可能还未初始化显然调用结果就是非法的 所以说只有B在A之前完成初始化程序才能正确运行而这种跨编译单元的初始化顺序编译器是无法保证的

              四饿汉模式增强版本boost实现

              在前面的方案中饿汉模式中使用到了类静态成员变量但是遇到了初始化顺序的问题 懒汉模式中使用到了静态局部变量但是存在着线程安全等问题

              boost 的实现方式是单例对象作为静态局部变量然后增加一个辅助类并声明一个该辅助类的类静态成员变量在该辅助类的构造函数中初始化单例对象以下为代码

              class Singleton
              {
              public:
                  static Singleton* GetInstance()
                  {
                      static Singleton instance;
                      return &instance;
                  }
              
              protected:
                  // 辅助代理类
                  struct Object_Creator
                  {
                      Object_Creator()
                      {
                          Singleton::GetInstance();
                      }
                  };
                  static Object_Creator _object_creator;
              
                  Singleton() {}
                  ~Singleton() {}
              };
              
              Singleton::Object_Creator Singleton::_object_creator; 

              首先代理类这个外部变量初始化时在其构造函数内部调用Singleton::GetInstance();从而间接完成单例对象的初始化这就通过该代理类实现了饿汉模式的特性

              其次仍然考虑第三种模式的缺陷 当A的初始化依赖于B 即A的构造函数中要调用B::GetInstance() 而此时B::m_instance 可能还未初始化显然调用结果就是非法的 现在就变为在A的构造函数中要调用B::GetInstance() 如果B尚未初始化就会引发B的初始化所以在不同编译单元内全局变量的初始化顺序不定的问题就随之解决

              最后关于使用懒汉还是饿汉模式我的理解

              如果这个单例对象构造十分耗时或者占用很多资源比如加载插件啊 初始化网络连接啊读取文件啊等等而有可能该对象程序运行时不会用到那么也要在程序一开始就进行初始化也是一种资源浪费吧 所以这种情况懒汉模式延迟加载更好

              如果这个单例对象在多线程高并发环境下频繁使用性能要求较高那么显然使用饿汉模式来避免资源竞争提高响应速度更好

              点击复制链接 与好友分享!回本站首页
              上一篇C++编程之引用和拷贝构造函数按值传递和返回位拷?#20174;?#21021;始化等实例
              下一篇最后一页
              相关文章
              图文推荐
              点击排行

              关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报?#34892;?/a>

              版权所有: 红黑联盟--致力于做实用的IT技术学习网站

              ٷͧü
              <dl id="opymh"></dl>

              <div id="opymh"></div>
                  <div id="opymh"><tr id="opymh"></tr></div>

                    <em id="opymh"><ins id="opymh"><mark id="opymh"></mark></ins></em><sup id="opymh"><menu id="opymh"></menu></sup>

                    <em id="opymh"></em>

                    <em id="opymh"><ol id="opymh"></ol></em>

                          <dl id="opymh"></dl>

                          <div id="opymh"></div>
                              <div id="opymh"><tr id="opymh"></tr></div>

                                <em id="opymh"><ins id="opymh"><mark id="opymh"></mark></ins></em><sup id="opymh"><menu id="opymh"></menu></sup>

                                <em id="opymh"></em>

                                <em id="opymh"><ol id="opymh"></ol></em>