中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

c++單例模式 ---超詳細

發布時間:2020-06-28 19:55:02 來源:網絡 閱讀:650 作者:ye小灰灰 欄目:移動開發


一.概述:

  因為在設計或開發中,肯定會有這么一種情況,一個類只能有一個對象被創建,如果有多個對象的話,可能會導致狀態的混亂和不一致。這種情況下,單例模式是最 恰當的解決辦法。有很多地方需要這樣的功能模塊,如系統的日志輸出,GUI應用必須是單鼠標,MODEM的聯接需要一條且只需要一條電話線,操作系統只能有一個窗口管理器,一臺PC連一個鍵盤。單例模式有很多種實現方式,各自的特性不相同,使用的情形也不相同。今天要實現的是常用的三種,分別是餓漢式、懶漢式和多線程式。

  《設計模式》一書中的實現有三個要素,定義一個單例類,要使用類的私有靜態指針變量指向類的唯一實例(即在類中就生成一個對象),并用一個公有的靜態方法獲取該實例,并把構造函數定義為protected或private。




二.懶漢式實現單例模式:

懶漢式的特點是延遲加載,懶漢么,很懶,它只在要用到實例時才加載實例。

 /****************************************                                   
  2     > File Name:lanhan.cpp
  3     > Author:xiaoxiaohui
  4     > mail:1924224891@qq.com
  5     > Created Time:2016年05月07日 星期六 15時01分25秒
  6 ****************************************/
  7 
  8 #include<iostream>
  9 using namespace std
 10 
 11 class Singleton
 12 {
 13 private:
 14     Singleton()
 15     {}
 16     static Singleton* _instace;   //靜態的  私有的
 17 public:
 18     static Singleton* GetInstace()
 19     {
 20         if(_instance == NULL)
 21         {
 22             _instance = new Singleton();
 23         }
 24         return _instance;   //如果非空則new一個對象 后者返回原來的兩個對象(所以保證了只有一個對象生成)   
 25     }
 26  
 27 }
 28

上面的這一實現存在內存泄露問題,因為沒有釋放_instance指針,下面為懶漢式的改進版:

 8 #include<iostream>
  9 using namespace std
 10 
 11 class Singleton
 12 {
 13 private:
 14     Singleton()
 15     {}
 16     static Singleton* _instance;   //靜態的  私有的
 17 
 18     class del
 19     {
 20     public:
 21         ~del()
 22         {
 23             if(Singleton::_instance != NULL)
 24             {
 25                 delete Singleton::_instance;
 26                 Singleton::_instance = NULL;
 27             }
 28         }
 29     }
 30     static del d;  //靜態變量會在程序結束時調用它的析構函數
 31 public:
 32     static Singleton* GetInstance()
 33     {
 34         if(_instance == NULL)
 35         {
 36             _instance = new Singleton();
 37         }
 38         return _instance;   //如果非空則new一個對象 后者返回原來的兩個對象(所以保證了只有一個對象生成)   
 39     }
 40 
 41 }

該實現會在程序結束時調用靜態變量的析構函數,從而delete了唯一的Singleton對象。

使用這種方法釋放單例對象有以下特征:
1.在單例類內部定義專有的嵌套類。
2.在單例類內定義私有的專門用于釋放的靜態成員。
3.利用程序在結束時析構全局變量的特性,選擇最終的釋放時機。


但是現在還有問題,如果在多線程環境下,因為“if(_instance == NULL)”并不是原子的,會存在線程安全問題(如果一個線程剛剛判斷了指針為空,這時另一個線程的優先級更高或者其它原因,打斷了原來線程的執行,再次判斷指針也會為空,所以會出現兩個實例)下面為多線程環境下的懶漢式單例模式:

 8 #include<iostream>
  9 #include<stdlib.h>
 10 #include<pthread.h>
 11 
 12 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
 13 using namespace std
 14 
 15 class Singleton
 16 {
 17 private:
 18     Singleton()
 19     {}
 20     static Singleton* _instance;   //靜態的  私有的
 21 
 22     class del
 23     {
 24     public:
 25         ~del()
 26         {
 27             if(Singleton::_instance != NULL)
 28             {
 29                 delete Singleton::_instance;
 30                 Singleton::_instance = NULL;
 31             }
 32         }
 33     }
 34     static del d;  //靜態變量會在程序結束時調用它的析構函數
 35 public:
 36     static Singleton* GetInstance()
 37     {
 38         pthread_mutex_lock(&lock);
 39         if(_instance == NULL)
 40         {
 41             _instance = new Singleton();
 42         }
 43         pthread_mutex_unlock(&lock);
 44         return _instance;   //如果非空則new一個對象 后者返回原來的兩個對象(所以保證了只有一個對象生成)   
 45     }
 46 
 47 }
 48

但現在還有問題,當有大量的線程時,只會有一個線程進入互斥鎖,然后執行下面的代碼而其它線程只能等待,并且加鎖是一個繁重的過程,這樣會導致加很多次鎖,這樣就太不高效了。下面是高效版的多線程環境下的懶漢式單例模式:

 8 #include<iostream>
  9 #include<stdlib.h>
 10 #include<pthread.h>
 11 
 12 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
 13 using namespace std
 14 
 15 class Singleton
 16 {
 17 private:
 18     Singleton()
 19     {}
 20     static Singleton* _instance;   //靜態的  私有的
 21 
 22     class del
 23     {
 24     public:
 25         ~del()
 26         {
 27             if(Singleton::_instance != NULL)
 28             {
 29                 delete Singleton::_instance;
 30                 Singleton::_instance = NULL;
 31             }
 32         }
 33     }
 34     static del d;  //靜態變量會在程序結束時調用它的析構函數
 35 public:
 36     static Singleton* GetInstance()
 37     {
 38         if(_instance == NULL)
 39         {
 40              pthread_mutex_lock(&lock);
 41              if(_instance == NULL)
 42              {
 43                 _instance = new Singleton();
 44              }
 45              pthread_mutex_unlock(&lock);
 46         }
 47         return _instance;   //如果非空則new一個對象 后者返回原來的兩個對象(所以保證了只有一個對象生成)   
 48     }
 49 
 50 }

這樣只有沒有Singleton實例時才會進入加鎖的代碼,而當有Singleton實例時不需要進入加鎖的代碼中,直接返回已存在的實例就行了。




三.餓漢式的單例模式:在一開始就創建實例,要用時直接返回即可。餓汗式的單例模式沒有線程安全問題,因為所以線程都只能訪問一個已存在的對象,無論線程怎么調度都不會有多個對象出現。因為對象是一個靜態變量(不是指針),會在程序結束時自動調用它的析構函數,所以不用考慮內存泄露問題。

餓汗式的特點:代碼簡單,不會出現內存泄露,是線程安全的。

  1 /****************************************
  2     > File Name:erhan.cpp
  3     > Author:xiaoxiaohui
  4     > mail:1924224891@qq.com
  5     > Created Time:2016年05月07日 星期六 16時10分56秒
  6 ****************************************/
  7 
  8 #include<iostream>
  9 using namespace std
 10 
 11 
 12 class Singleton
 13 {
 14 private:
 15     Singleton()
 16     {}
 17     static Singleton instance ;    //靜態變量只會有一份數據存在 從而保證只有一個實例
 18 public:
 19     static Singleton& GetInstance()
 20     {
 21         return instance;                                                   
 22     }   
 23 }

聲明一個局部的靜態變量,而靜態變量在全局范圍內只有一份數據,所以無論調用多少此GetInstance,返回的都是那一個實例。

但這個實現存在問題,Singleton singleton = Singleton :: GetInstance(),這么做就出現了一個類拷貝的問題,這就違背了單例的特性。產生這個問題原因在于:因為在這里沒有實現拷貝構造函數,編譯器會為類生成一個默認的拷貝構造函數,來支持類的拷貝。

解決方法:1.自己再定義一個拷貝構造函數和operator=,這個拷貝構造函數和operator=什么都不做。

2.返回一個Singleton指針。

下面為方法2的代碼:

  8 #include<iostream>
  9 using namespace std
 10 
 11 
 12 class Singleton
 13 {
 14 private:
 15     Singleton()
 16     {}
 17     static Singleton instance ;    //靜態變量只會有一份數據存在 從而保證只有一個實例
 18 public:
 19     static Singleton* GetInstance()
 20     {
 21         return &instance;                                                   
 22     }   
 23 }



總結:單例模式適用于只允許一個實例存在的情況,它的實現必須滿足三個條件,一是必須在類中就定義一個實例;二是必須有一個公有的靜態方法來獲取該實例;三是構造函數必須是私有的,來保證不容許別人通過調用構造函數來生成一個實例。在實現時要注意內存泄露問題,線程安全問題,性能問題。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

天镇县| 冷水江市| 阜阳市| 桃源县| 太仓市| 建瓯市| 临沭县| 资溪县| 衢州市| 昌平区| 黔东| 册亨县| 岫岩| 沅陵县| 海盐县| 丰原市| 西平县| 房山区| 安岳县| 乌兰察布市| 中阳县| 宝丰县| 同仁县| 万荣县| 临武县| 扶沟县| 蒙阴县| 乐业县| 黄陵县| 曲麻莱县| 高清| 木兰县| 桦川县| 志丹县| 工布江达县| 金门县| 沂源县| 吴江市| 霍林郭勒市| 涞源县| 甘泉县|