1. 程式人生 > >C++深入理解單例模式詳解

C++深入理解單例模式詳解

作者:知乎使用者
連結:https://www.zhihu.com/question/27704562/answer/37760739
來源:知乎
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。


不使用編譯器擴充套件,不用C++11,不加鎖,也不使用原子操作的話,
那必須有個條件就是main函式執行之前程式必須是單執行緒的,不然真不行,再百度也不行,
如果有符合以上條件的單例類且不要求main之前是單執行緒的,請告訴我....然後:
這是2b單例:template<typename T>
class Im2Bsingleton
{
public:
    static T* get() { 
       if(ptr==nullptr) { ptr=new T; }
       return ptr; 
    };
private:
    static T* ptr;
};
這個顯然不是執行緒安全的,因為ptr會在第一次被使用的時候new T,
而第一次被使用的時候8成是main之後了,就很可能是多執行緒情況下,
那麼可以使用一個原子操作:template<typename T>
class AtomicSingleton
{
public:
    static T* get() {
       for(;;) {
           T* k=nullptr; 
           ptr.compare_exchange_weak(k,(T*)&place_holder); 
           if(k==0){ 
                k=new T;
                ptr.set(k);//此處必然成功
                return k;
           } else if(k==(T*)&place_holder) {
                //別的執行緒佔坑了,等著去吧!
           } else {
                return k;
           }
       }
    };
private:
    static atomic<T*> ptr;
    static char place_holder;
};
代價是一次CAS和一次判斷,但是題目說了不能加鎖或者原子操作,那麼,
再說一遍就是必須保證main函式執行之前不能存在多執行緒情況,
可以這樣:template<typename T>
class Singleton
{
public:
    static T* get() { 
       return ptr; 
    };
private:
    static T* ptr;
};
你肯定覺得這個不對啊,ptr沒被構造啊,對,保證前提的基礎上,
我們只需要保證ptr能在main之前絕逼被構造就行了,
我們需要一個helper:普通單例
:template<typename T>
class Singleton
{
private:
    struct ShitCleanHelper {
        ShitCleanHelper(){ Singleton<T>::ptr=new T; }
        ~ShitCleanHelper(){ 
            delete Singlenton<T>::ptr; 
            Singlenton<T>::ptr=nullptr;
        }
    };
public:
    static T* get() { 
       return ptr; 
    };
private:
    static T* ptr;
    static ShitCleanHelper helper;
    friend class ShitCleanHelper;
};
由於helper是static的,根據C++標準,靜態物件被保證在main之前構造,
因此ShitCleanHelper被絕對保證在main之前構造,它在構造時候不幹任何事,
只負責new T.這樣,當進入main之後,ptr肯定就指著正確的物件了.
你會說那又不對了,這樣雖然能夠保證Singlenton在main之前new,
但是萬一我需要在main之前就要用get()怎麼辦? 
又或者,我的模組與模組之間不同的static物件互相有互動,這一切都發生在main之前,怎麼辦?
下面是文藝單例:template<typename T,bool DirectConstruction = true>
class ScopedSingleton
{
private:
    class InstanceCreator {
    public:
        InstanceCreator() :m_ptr(new T) {};
        ~InstanceCreator() { delete m_ptr; };
        operator T&() noexcept { return *m_ptr;}
    private:
        T* RESTRICT const m_ptr;
    };
    class DummyInstanceUser
    {
    public:
        DummyInstanceUser(){ ScopedSingleton::getInstance(); }
        ~DummyInstanceUser() { ScopedSingleton::getInstance(); }
        void DoNothing(){}
    };
public:
    static T& getInstance()
    {
        static InstanceCreator m_instancePtr;
        m_dummyUser.DoNothing(); 
        //此處似乎是模板的一個bug,加了這一句才能保證main之前m_instancePtr一定被構造.
        return m_instancePtr;
    };
private:
    ScopedSingleton(){ getInstance(); }
    ~ScopedSingleton(){ getInstance(); }
private:
    static DummyInstanceUser m_dummyUser;
};
首先,C++保證函式內的static變數保證在它第一次被使用之前被構造,
這就避免了"普通單例"中可能在ShitCleanHelper構造new T之前就要使用的尷尬局面.
無論什麼時候要用它,它肯定會在這之前被構造了,但是這樣一來又有問題了,
假如main函式之前誰都不用它,而main之後才有人第一次用到它,
那還怎麼保證它在main之前被構造以避免多執行緒問題呢? 
這就需要DummyInstanceUser出現了, DummyInstanceUser存在的唯一一個例項是m_dummyUser,
由於它是static的,所以它保證了在main函式之前被構造,而它的建構函式的唯一目的就是"假裝使用了m_instancePtr",
這樣即使沒有人再main之前呼叫getInstance(),DummyUser依然會作為main之前的最後一道屏障保證在main之前一定構造成功.同時,這種單例還避免了跨模組的static變數互相引用的問題,例如有不同的單例A和B,它們在兩個不同的cpp中,則它們的構造順序雖然都在main之前,但互相之間的順序是不確定的,但是使用這種文藝單例,如果A需要用到B,請看這一段文字的第一句話,只要A會用到B,B就會保證在A之前構造.

相關推薦

C++深入理解模式

作者:知乎使用者連結:https://www.zhihu.com/question/27704562/answer/37760739來源:知乎著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。不使用編譯器擴充套件,不用C++11,不加鎖,也不使用原子操作的話

模式

餓漢式 登記式 懶漢式 單例 單例設計模式Singleton是一種創建型模式,指某個類采用Singleton模式,則在這個類被創建後,只可能產生一個實例供外部訪問,並且提供一個全局的訪問點。核心知識點如下:(1) 將采用單例設計模式的類的構造方法私有化(采用private修飾)。(2) 在其

模式及java常用類

ont 獲得 設計 保持 BE RR instance tro 函數 【單例模式】 確保某一個類,只能產生一個實例。 設計思路: ====將構造函數私有化,確保類外部,不能使用new關鍵字自行創建對象。 ====在類內部實例化一個對象,並通過靜態方法返回。 (1)

跟著別人學設計模式-----(一)模式

    作者:zuoxiaolong8810(左瀟龍),轉載自:http://www.cnblogs.com/zuoxiaolong/p/pattern2.html             上一章

設計模式(一)模式

愉快的開始自己的技術積累 ,設計模式中使用最普遍的單例模式開始; 設計模式中最為大家熟悉的必須是單例模式,專案中 必須 使用到的套路。首先陳述下我對 框架,模式的一些理解。   從學校出來,開始面試的時候張口框架,閉口模式,真的問道什麼是框架,我只能死鴨子嘴硬的強調 MVC ,

ios 模式

單例:在寫專案的時候,我們實際用到了很多系統給我們提供的單例類; 如: [UIApplication sharedApplication]; //應用程式例項類 [NSNotificationCenter defaultCenter];//訊息中心例項類 [NSFileMana

設計模式模式

單例模式寫法大全,也許有你不知道的寫法 導航 引言 什麼是單例? 單例模式作用 單例模式的實現方法 引言 單例模式想必是大家接觸的比較多的一種模式了,就算沒用過但是肯定聽過他的鼎鼎大名了。在我初入程式設計界時聽到最多的就是單例模式,工廠模式,觀察者模式了。特別是觀察者模

設計模式(建立型):Java常用23種設計模式模式以及Java程式碼實現

可以說單例模式是所有設計模式中最簡單的一種。 單例模式就是說系統中對於某類的只能有一個物件,不可能出來第二個。 單例模式也是23中設計模式中在面試時少數幾個會要求寫程式碼的模式之一。主要考察的是多執行緒下面單例模式的執行緒安全性問題。 1.多執行緒安全單例模式例項一(不使用同步鎖)

OC模式

單例模式 有時候我們需要一個全域性的物件,而且要保證全域性有且僅有一份即可,這時候就需要用到單例設計模式,但是需要注意的是:在多執行緒的環境下也需要做好執行緒保護。其實系統已經有很多單例存在,例如UIApplication、NSNotification、NSFileMa

深入理解模式(上)

最近在閱讀《 》這本書,第3個條款專門提到了單例屬性,並給出了使用單例的最佳實踐建議。讓我對這個單例模式(原本我以為是設計模式中最簡單的一種)有了更深的認識。 單例模式 單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種型別的設計模式屬

深入理解模式:靜態內部類原理

這樣的 加載 hand 優點 傳遞 多個 喚醒 ref 一個   本文主要介紹java的單例模式,以及詳細剖析靜態內部類之所以能夠實現單例的原理。OK,廢話不多說,進入正文。    首先我們要先了解下單例的四大原則:    1.構造私有。    2.以靜態方法或者枚舉返回實

深入理解模式的幾種實現方式

前言 單例模式是一種很常用的設計模式,其定義是單例物件的類只允許有一個例項存在。在使用spring自動建立物件時預設就是單例的。 使用場景 需要頻繁的對物件進行建立與銷燬,如果工具類物件 一、餓漢式(靜態變數) public class Singleton1 { private st

一篇很不錯的模式

1、什麼是設計模式?       首先我們來看第一個問題什麼是設計模式?在百度百科中它的定義是這樣的: 設計模式(Design pattern)是一套被反覆使用、多數人知曉的、經過分類編目的、程式碼設計經驗的總結。(百度百科)   &nb

深入理解模式——只有一個例項

目錄: 前言 初遇設計模式在上個寒假,當時把每個設計模式過了一遍,對設計模式有了一個最初級的瞭解。這個學期借了幾本設計模式的書籍看,聽了老師的設計模式課,對設計模式算是有個更進一步的認識。後面可能會不定期更新一下自己對於設計模式的理解。每個設計模式看似很簡單,

模式(餓漢式,懶漢式,登記式,列舉式,序列化和反序列)

一、單例模式應用場景:保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。 應用場景:保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。 Spring 中的單例模式完成了後半句話,即提供了全域性的訪問點 BeanFactory。但沒有從構造器級別去 控制單例,這是

【Java】設計模式深入理解模式

什麼是設計模式?簡單的理解就是前人留下來的一些經驗總結而已,然後把這些經驗起了個名字叫Design Pattern,翻譯過來就是設計模式,通過使用設計模式可以讓我們的程式碼複用性更高,可維護性更高,讓你的程式碼寫的更優雅。設計模式理論上有23種,今天就先來

深入理解模式

在GoF的23種設計模式中,單例模式是比較簡單的一種。然而,有時候越是簡單的東西越容易出現問題。下面就單例設計模式詳細的探討一下。 所謂單例模式,簡單來說,就是在整個應用中保證只有一個類的例項存在。就像是Java Web中的application,也就是提供了一個全域性變數,用處相當廣泛,比如儲存全域性資

java中工廠模式模式

如何將例項化具體類的程式碼從應用中抽離或者封裝起來,使它們不會干擾應用的其他部分? 1:簡單工廠模式:其作用是例項化物件而不需要客戶瞭解這個物件屬於那個具體的子類。 using System; using System.Collections; public class MyClass {  

Java模式

概念:    java中單例模式是一種常見的設計模式,單例模式分三種:懶漢式單例、餓漢式單例、登記式單例三種。    單例模式有一下特點:   1、單例類只能有一個例項。   2、單例類必須自己自己建立自己的唯一例項。   3、單例類必須給所有其他

Android 常用設計模式(二) -- 模式()

上一篇講到策略模式,變動的程式碼需要用到策略模式,感興趣的小夥伴可以看看. 傳送門:Android 常用設計模式之 – 策略模式 單例模式的定義就不解釋過多了,相信很多小夥伴在設計的時候,都用到這個模式;常用的場景為 資料庫的訪問,檔案流的訪問以及網路連