下面是對應的c++單例模式物件推導過程,如果大家有興趣可以慢慢看下去,想直接看結果的請看最後乙個版本的**。
#pragma
#include
class
csingletion
return m_pstaticsingletion;
}//todo 實現功能
void
work()
;private
:csingletion()
;csingletion
(const csingletion &);
csingletion&
operator=(
const csingletion&);
static csingletion* m_pstaticsingletion;};
csingletion* csingletion::m_pstaticsingletion =
nullptr
;//類靜態成員需要外部初始化
缺點:沒有執行緒安全,多執行緒併發同時呼叫getinstance函式,會出現問題。
無法自動析構,會存在記憶體洩漏
#pragma
#include
#include
class
csingletion1
return m_pstaticsingletion;
}//todo 實現功能
void
work()
;private
:static
void
deleteinstance()
}csingletion1()
;csingletion1
(const csingletion1&);
csingletion1&
operator=(
const csingletion1&);
static csingletion1* m_pstaticsingletion;};
csingletion1* csingletion1::m_pstaticsingletion =
nullptr
;//類靜態成員需要外部初始化
解決了自動析構的問題,
還可使用智慧型指標,內部類,區域性靜態例項化物件(而非指標,靜態物件儲存在全域性資料段,系統會自動釋放)來解決自動析構的問題。
#pragma
#include
#include
#include
class
csingletion
return m_pstaticsingletion;
}//todo 實現功能
void
work()
;private
:static
void
deleteinstance()
}csingletion()
;csingletion
(const csingletion&);
csingletion&
operator=(
const csingletion&);
static csingletion* m_pstaticsingletion;
static std::mutex m_mutex;};
csingletion* csingletion::m_pstaticsingletion =
nullptr
;//類靜態成員需要外部初始化
std::mutex csingletion::m_mutex;
新增乙個鎖那麼就可以解決執行緒安全的問題,一般開發都會使用這種方式。
#pragma
#include
#include
#include
class
csingletion4
}return m_pstaticsingletion;
}//todo 實現功能
void
work()
;private
:static
void
deleteinstance()
}csingletion4()
;csingletion4
(const csingletion4&);
csingletion4&
operator=(
const csingletion4&);
static csingletion4* m_pstaticsingletion;
static std::mutex m_mutex;};
csingletion4* csingletion4::m_pstaticsingletion =
nullptr
;//類靜態成員需要外部初始化
std::mutex csingletion4::m_mutex;
所以我們可以將鎖放在if(null == **)的語句的下面,如此,相比較版本三的**,不管m_pstaticsingletion 是否為空,進來就加一次鎖,版本四隻會在m_pstaticsingletion 為空時加鎖,會好很多, 那我們來討論一種情況,當m_pstaticsingletion為空時,兩個執行緒同時呼叫getinstance函式,第乙個執行緒的函式呼叫,已經進入到鎖中了,
這裡說明兩個知識點
m_pstaticsingletion = new csingletion4();這條語句翻譯為彙編指令或者說cpu指令主要分為三個過程,1.分配記憶體,2.呼叫建構函式, 3將記憶體首位址賦給m_pstaticsingletion 。綜上所述,咱們的不可重入版本4的**還是存在瑕疵, 所以引出了版本五,
#pragma
#include
#include
#include
#include
class
csingletion5
}return m_pstaticsingletion;
}//todo 實現功能
void
work()
;private
:static
void
deleteinstance()
}csingletion5()
;csingletion5
(const csingletion5&);
csingletion5&
operator=(
const csingletion5&);
static std::atomic> m_pstaticsingletion;
static std::mutex m_mutex;};
std::atomic> csingletion5::m_pstaticsingletion =
nullptr
;//類靜態成員需要外部初始化
std::mutex csingletion5::m_mutex;
使用c++11提供的原子控制類atomic,加上記憶體屏障,防止cpu指令reorder,這個時候大家可能會覺得這個**過於複雜,有沒有更簡單一點的方法呢,有的看**六
#pragma
//c++ 11 magic static 特性 當變數在初始化的時候,並且同時進入宣告語句是,併發執行緒會阻塞等待初始化結束。
class
csingletion6
//todo 實現功能
void
work()
;private
:csingletion6()
;csingletion6
(const csingletion6&);
csingletion6&
operator=(
const csingletion6&);
};
這個**看起來是非常的清爽了,非常的舒服,但是這個**還是存在一些問題,因為建構函式是私有的·所以會造成無法繼承以及拓展性太差的問題,為了解決這個問題我們提出了**7,
#pragma once
//c++ 11 magic static 特性 當變數在初始化的時候,並且同時進入宣告語句是,併發執行緒會阻塞等待初始化結束。
template
<
typename t>
class
csingletion7
virtual
~csingletion7()
//todo 實現功能
void
work()
;protected
:csingletion7()
;csingletion7
(const csingletion7&);
csingletion7&
operator=(
const csingletion7&);
};class
csingletion8
:public csingletion7
;
大家仔細看這個模板類的**,我們將基類的建構函式可見性修改為protected,目的是為了讓派生類可以訪問到基類的建構函式,而將子類定義為派生類的友元類,是為了在基類中能夠訪問派生類的建構函式,這樣我們在基類中定義了乙個派生類物件,且該物件是唯一的,該物件既可以訪問派生類的所有方法也可以訪問子類的所有方法,至此大功告成。 C 單例模式詳解
三 餓漢式單例 參考文章 設計模式 一 深入單例模式 涉及執行緒安全問題 全,解釋清楚。本篇部落格編譯時,需要使用c 11標準。1 定義 要求乙個類只能生成乙個物件,所有物件對它的依賴相同。2 優點 3 缺點 4 使用場景 5 注意事項 懶漢式單例就是需要使用這個單例物件的時候才去建立這個單例物件。...
單例模式詳解
單例模式的意思就是只有乙個例項。單例模式確保某乙個類只有乙個例項,而且自行例項化並向整個系統提供這個例項。這個類稱為單例類。1.單例模式的要點 顯然單例模式的要點有三個 一是某個類只能有乙個例項 二是它必須自行建立這個例項 三是它必須自行向整個系統提供這個例項。2.單例模式的優點 1.例項控制 si...
單例模式詳解
單例模式是設計模式中比較常用的,今天我要詳細的了解一下,並且進行一些比較 public class singleton public static singleton getinstance catch interruptedexception e 單例模式的精髓就在這,類的內部可以new inst...