我們在設計某些類時,根據需求,有時只需要乙個例項,不想過多浪費記憶體,這就可以通過單例項的方式。
如,我們在使用windows的任務管理器時,彈出的始終是乙個視窗,
這裡如果物件採用多例項模式,那麼就會彈出多個視窗,會出現下述兩種情況:
第一,如果這些視窗顯示的內容不一致,則意味著在某一瞬間系統有多個狀態,
容易使使用者誤解,不知道哪乙個才是真實的狀態,這與需求不符;
第二,如果這些視窗顯示的內容完全一致,則是重複物件,意味著浪費記憶體資源。
因此有時確保系統中某個物件的唯一性即乙個類只能有乙個例項非常重要。
單例項模式,應該有如下特點:
第一,這個類只能建立乙個物件;
第二,這個類必須自行建立這個物件;
第三,這個類建立的物件必須在整個系統都可以使用。
單例項上述特點的實現方式:
第一,是這個類只提供私有的建構函式;
第二,是這個類定義中含有乙個該類的靜態私有物件;
第三,是這個類提供了乙個靜態的公有的函式用於建立或獲取它本身的靜態私有物件。
思考:
singleton模式經常和factory(abstractfactory)模式在一起使用,
因為系統中工廠物件一般來說只要乙個
需要考慮:
第一,只有乙個物件,則需要禁止copying行為(包括拷貝和賦值)。
第二,如果是動態申請資源,則需要考慮資源的釋放。
第三,多執行緒安全,即同一時刻多個執行緒呼叫這個函式會不會出現程式異常。
(1) 懶漢式
懶漢式的方式就是延遲載入,即定義乙個指向該類的私有指標,
直到用到例項的時候才進行物件的建立,並把物件位址賦值給這個指標。
第一種方式:申請的資源手動釋放
############# test.h #############
class test
;
############# test.cpp #############
test* test::m_ptest = null;
lock test::m_slock;
/* * 建構函式
*/test::test()
/* * 析構函式
*/test::~test()
//建立單例項物件
test* test::getinstance()
test::m_slock.mutexunlock();
return m_ptest;
}//銷毀test, 注:必須在所有執行緒結束後,程序結束前呼叫
void test::destroyinstance()
說明:1. 建立例項,getinstance()
2. 銷毀例項,destroyinstance()
3. 在懶漢式的單例類中,其實有兩個狀態,單例未初始化和單例已經初始化。
假設單例還未初始化,有兩個執行緒同時呼叫
getinstance
方法,這時執行
m_ptest == null
肯定為真,
然後兩個執行緒都初始化乙個單例,最後得到的指標並不是指向同乙個地方,
不滿足單例類的定義了,所以懶漢式的寫法會出現執行緒安全的問題!
在多執行緒環境下,要對其進行修改,例如,上面進行加鎖處理,
以此來保證只有乙個例項。
4. 建構函式為私有的好處:
禁止使用者對此型別的變數進行定義,即禁止在類外建立此型別的物件。
5. 析構函式為私有的好處:
禁止使用者在程式中使用 delete 刪除此型別物件。
物件的刪除只能在類內實現,也就是說只有類的實現者才有可能實現對物件的 delete,
使用者不能隨便刪除物件。如果使用者想刪除物件的話,只能按照類的實現者提供的方法進行。
第二種:申請的資源自動釋放(這種方式有點多餘,程式結束,系統自動**記憶體,只是一種思考)
############# test.h #############
class test
} };
private:
//全域性唯一物件指標
static test* m_ptest;
//定義乙個靜態成員變數,程式結束時,系統會自動呼叫它的析構函式
static garbo m_sgarbo;
static lock m_slock;
};
############# test.cpp #############
test* test::m_ptest = null;
garbo test::m_sgarbo;
lock test::m_slock;
/* * 建構函式
*/test::test()
/* * 析構函式
*/test::~test()
//建立單例項物件
test* test::getinstance()
test::m_slock.mutexunlock();
return m_ptest;
}
說明:1.建立例項,getinstance()
2.不需要手動釋放資源,通過靜態物件m_sgarbo的析構函式自動釋放
第三種:(推薦使用方式)
補充:已初始化的的全域性變數和區域性靜態變數存放在data段,
未初始化的全域性變數和區域性靜態變數一般存放在bss段裡,
前者在生產可執行檔案時就分配好記憶體了,後者在載入時才分配。
注意:所謂static物件指的是內存在data段和bss段中的物件.這類物件在整個程式的生命週期內都是存在的,除非程式結束否則會一直存在,
利用static關鍵字宣告的物件是static物件中的一種,但是如果是在函式內部定義的static物件,那麼這種static物件被稱為local static物件,
除此之外的則是non-local static物件,比如:global作用域內的static物件,namespace作用域內的static物件,
類作用域內使用static關鍵字宣告的物件,file作用域內的static物件等.
local static物件的乙個特性就是不會在編譯的時候自動初始化,然後在呼叫函式的時候碰到local static物件定義的時候才會對其進行初始化。
從另外乙個角度來看,任何一種 non-const static 物件,不論是local 或者non-local ,在多執行緒環境下「等待某事發生」都會有麻煩。
處理這個麻煩的做法是:(1) 可以在程式的單執行緒啟動階段手工呼叫;(2) 也可以通過加鎖的方式解決多執行緒的問題。
############# test.h #############
class test
;
############# test.cpp #############
/*
* 建構函式
*/test::test()
/* * 析構函式
*/test::~test()
/* * 單例項實現
*/test* test:getinstance()
說明:1.使用單例getinstance()
2.不用資源釋放問題
(2) 餓漢式
餓漢式的方式是一開始就載入了,以空間換時間,
即定義乙個靜態的私有物件。不存在多執行緒問題。
class singleton
private:
static singleton* p;
public:
static singleton* initance();
};singleton* singleton::p = new singleton;
singleton* singleton::initance()
單例模式詳解
單例模式的意思就是只有乙個例項。單例模式確保某乙個類只有乙個例項,而且自行例項化並向整個系統提供這個例項。這個類稱為單例類。1.單例模式的要點 顯然單例模式的要點有三個 一是某個類只能有乙個例項 二是它必須自行建立這個例項 三是它必須自行向整個系統提供這個例項。2.單例模式的優點 1.例項控制 si...
單例模式詳解
單例模式是設計模式中比較常用的,今天我要詳細的了解一下,並且進行一些比較 public class singleton public static singleton getinstance catch interruptedexception e 單例模式的精髓就在這,類的內部可以new inst...
單例模式 詳解
保證乙個類僅有乙個例項,並且提供乙個訪問它的全域性訪問點 在該例項不存在的情況下,可以通過乙個方法建立乙個類來實現建立類的新例項 如果例項已經存在,它會簡單返回該物件的引用 建立型模式 var singleton function return var singlea singleton.getin...