單例模式(經典)

2021-08-08 08:32:47 字數 2845 閱讀 7865

一 、定義

眾多設計模式中,單例模式是一種比較常見模式。本文以乙個c++開發者的角度分析單例模式的幾種經典實現。

gof定義單例模式需滿足以下兩個條件:

1、保證乙個類只建立乙個例項。

2、提供對例項的全域性訪問點。

二、應用場景

日誌類、配置類、管理類、共享資源類

三、單例的幾種實現

3.1 lazy singleton

//標頭檔案中

class singleton

return *instance_;

}private:

singleton();

~singleton();

singleton(const singleton&);

singleton& operator=(const singleton&);

private:

static singleton* instance_;

};//實現檔案中

singleton* singleton::instance_ = 0;

優點:這裡instance()返回的例項的引用而不是指標,如果返回的是指標可能會有被外部呼叫者delete掉的隱患,所以這裡返回引用會更加保險一些。並且直到instance()被訪問,才會生成例項,這種特性被稱為延遲初始化(lazy initialization),這在一些初始化時消耗較大的情況有很大優勢。

缺點:lazy singleton不是執行緒安全的,比如現在有執行緒a和執行緒b,都通過instance_ == null的判斷,那麼執行緒a和b都會建立新例項。單例模式保證生成唯一例項的規則被打破了。

3.2 eager singleton

這種實現在程式開始(靜態屬性instance初始化)的時就完成了例項的建立。這正好和上述的lazy singleton相反。

//標頭檔案中

class singleton

private:

singleton();

~singleton();

singleton(const singleton&);

singleton& operator=(const singleton&);

private:

static singleton instance;

}//實現檔案中

singleton singleton::instance;

由於在main函式之前初始化,所以沒有執行緒安全的問題,但是潛在問題在於no - local static物件(函式外的static物件)在不同編譯單元(可理解為cpp檔案和其包含的標頭檔案)中的初始化順序是未定義的。如果在初始化完成之前呼叫 instance()方法會返回乙個未定義的例項。

2.3 meyers singleton

scott meyers在《effective c++》(item 04)中的提出另一種更優雅的單例模式實現,使用local static物件(函式內的static物件)。當第一次訪問instance()方法時才建立例項。

class singleton

private:

singleton();

~singleton();

singleton(const singleton&);

singleton& operator=(const singleton&);

};c++0x之後是該實現執行緒安全的,有興趣可以讀相關的標準草案(section 6.7)編譯器支援程度不一定, 但是g++4.0及以上是支援的。

2.4 雙檢測鎖模式(double - checked locking pattern)

lazy singleton的一種執行緒安全改造是在instance()中每次判斷是否為null前加鎖,但是加鎖是很慢的。

而實際上只有第一次例項建立的時候才需要加鎖。雙檢測鎖模式被提出來,改造之後大致是這樣

static singleton& instance()

}return *instance_;

}既然只需要在第一次初始化的時候加鎖,那麼在這之前判斷一下例項有沒有被建立就可以了,所以多在加鎖之前多加一層判斷,需要判斷兩次所有叫double - checked。理論上問題解決了,但是在實踐中有很多坑,如指令重排、多核處理器等問題讓dclp實現起來比較複雜比如需要使用記憶體屏障,詳細的分析可以閱讀這篇**。

在c++11中有全新的記憶體模型和原子庫,可以很方便的用來實現dclp。這裡不展開。有興趣可以閱讀這篇文章《double - checked locking is fixed in c++11》。

pthread_once在多執行緒程式設計環境下,儘管pthread_once()呼叫會出現在多個執行緒中,init_routine()函式僅執行一次,pthread_once是很適合用來實現執行緒安全單例。

template

class singleton : boost::noncopyable

static void init()

private:

static pthread_once_t ponce_;

static t* value_;

};template

pthread_once_t singleton::ponce_ = pthread_once_init;

template

t* singleton::value_ = null;

這裡的boost::noncopyable的作用是把建構函式, 賦值函式, 析構函式, 複製建構函式宣告為私有或者保護。

總結單例模式的實現方法很多,要寫乙個完美的實現很難**也會很複雜。但是掌握基礎的實現還是很必要的,然後在實際應用中不斷地去優化和探索。除了執行緒安全,一些場景下還有需要考慮資源釋放,生命週期等相關問題,可以參見《modern c++ design》中對singleton的討論

經典設計模式 單例模式

特點 單例類只能有乙個例項 單例類必須自己建立自己的唯一例項 單例類必須給所有其他物件提供這一物件例項 單例模式的應用場景 1.windows的task manager 任務管理器 就是很典型的單例模式 2.的計數器,一般也是採用單例模式實現,否則難以同步。3.應用程式的日誌應用,一般都何用單例模式...

PHP經典設計模式 單例模式 pfinal

class mysql 建立乙個用來例項化物件的方法,如果不存在乙個這個類的例項屬性,就建立乙個,否則就取這個例項屬性。public static function getinstance return self conn 防止物件被複製 public function clone 防止反序列化後建...

單例模式 單例模式

餓漢式 急切例項化 public class eagersingleton 2.宣告靜態成員變數並賦初始值 類初始化的時候靜態變數就被載入,因此叫做餓漢式 public static eagersingleton eagersingleton new eagersingleton 3.對外暴露公共的...