C 單例模式

2021-08-17 12:07:18 字數 3851 閱讀 1016

常見的設計模式:

介面卡模式、迭代器模式、工廠模式、單例模式、生成器模式、裝飾器模式、門面模式、**模式、橋接模式

介面卡模式

在之前學習棧和佇列時,我們發現棧和佇列的底層,並非自己實現,而是通過呼叫棧和佇列(庫中預設是雙端佇列)來實現的;以棧為例:我們在使用時不在乎,棧的底層實現,只要它能夠滿足尾插和尾刪即可。通過這種方法,更好的體現了stl庫的良好的復用性

迭代器模式

迭代器是stl庫中演算法和容器的紐帶,使用迭代器便可以用同一種方法對不同的容器進行訪問;迭代器類似與指標。迭代器的存在很好的保護了,物件導向的封裝性,減少了使用成本。

假如在沒有迭代器的情況下,如果要訪問紅黑樹的某乙個結點時,就必須滿足以下條件:

1、必須把其根節點暴露出來(這樣破壞了其的封裝性)

2、樹的訪問往往是通過遍歷來實現,不能直接訪問某個結點

3、要訪問某個結點,必須了解其底層實現(學習成本太大,不夠方便)

乙個類始終只能建立乙個例項,則這個類被稱為單例類,這種模式就被稱為單例模式。(執行緒安全且高效)

方法一、不考慮執行緒安全

#define _crt_secure_no_warnin  1

#pragma once

class singleton

return _inst;

} void print()

private:

singleton() //必須自己定義建構函式,且設為私有

:_a(0) //1.防止呼叫預設的建構函式 2、防止利用建構函式建立物件

singleton(const singleton&); //防拷貝,只宣告不定義

singleton& operator=(const singleton&); //防止進行深淺拷貝

private:

int _a;

static singleton* _inst; //靜態變數全域性只存乙份 ,此處的變數可以是 threadpool memorypool

};singleton* singleton:: _inst = null; //靜態變數必須在類外面,進行初始化

注意:

單例類的名字可以根據實際使用適當的名字,而非只能使用singleton;

單例類中的變數可以是執行緒池、記憶體池等(全域性只有乙份)等;

賦值運算子的過載不一定要設為私有,只在在一些情況下會存在深淺拷貝問題,因此最好設為私有;

方法二、考慮執行緒安全

上面所實現的單例類,在多執行緒的情況下,會出現執行緒安全問題

主要是由於下面的**引起:

static singleton* getinstance()  

return _inst;

}

在多核情況下:

當多個執行緒同時執行這段**時,每個執行緒都建立了乙個物件;這樣便不是全域性唯一的例項物件了;

在只有乙個cpu 的情況下:

說明:每乙個被cpu排程的執行緒,只能在時間片內執行;

由於以上**不是原子的,假設有兩個執行緒執行上述**:

首先執行緒一被排程 :在執行完 if(_inst == null) ,時間片用完了;這時執行緒二被排程: 在執行完  new singleton ,時間片用完了;執行緒一被再次排程,會執行 _inst = new singleton ,那麼此時執行緒一建立了乙個物件,並且執行緒二建立的物件被丟棄了,這時出現了問題。

普通版:

class singleton

_mtx.unlock();//解鎖

return _inst;

} void print()

private:

singleton()

:_a(0)

singleton(const singleton&);

singleton& operator=(const singleton&);

private:

int _a;

static singleton* _inst;

static mutex _mtx; //只有乙個鎖

};mutex singleton::_mtx ;//呼叫mutex的建構函式

singleton* singleton:: _inst = null;

上面所實現的單例類,存在一定的缺陷。如果在鎖之間的**出現異常時,便會導致沒有解鎖,導致大量的執行緒阻塞在_mtx.lock() 處,進而可能會出現死鎖。出現死鎖便是很危險的事情。可以對鎖資源,利用raii思想來解決此問題。

raii:資源獲得即初始化,資源在建構函式時初始化,自動呼叫析構函式,釋放資源。

class lock()

~lock()

private:

mutex& _mtx; //保證只有一把鎖

}

優化版:
class singleton

return _inst;

} void print()

private:

singleton()

:_a(0)

singleton(const singleton&);

singleton& operator=(const singleton&);

private:

int _a;

static singleton* _inst;

static mutex _mtx;

};mutex singleton::_mtx ;

singleton* singleton:: _inst = null;

注意:

1.此處可以自己通過raii思想實現乙個鎖,在c++11中提供了lock_guard類,也可以實現自動釋放

方法三、考慮安全和效率

方法二雖然解決了執行緒安全,但並不高效。

高效版:

class singleton

} return _inst;

} void print()

private:

singleton()

:_a(0)

singleton(const singleton&);

singleton& operator=(const singleton&);

private:

int _a;

static singleton* _inst;

static mutex _mtx; //只有乙個鎖

};mutex singleton::_mtx ; //呼叫mutex的建構函式

singleton* singleton:: _inst = null;

單例模式分類:

由分類可知:上面的單列模式都屬於懶漢模式。

餓漢模式:

class singleton

void print()

private:

singleton()

:_a(0)

singleton(const singleton&);

singleton& operator=(const singleton&);

static singleton* _inst = new singleton;

private:

int _a;

static mutex _mtx;

};mutex singleton::_mtx ;

比較:

懶漢模式:相對複雜,但在各種場景下都使用;

餓漢模式:簡結,但適用性有限制 例如:動態庫:只有在執行時才載入

C 單例模式

include using namespace std 單例類的c 實現 class singleton 構造方法實現 singleton singleton void singleton setvar int var main int main int argc,char argv return ...

C 單例模式

實現方式一 include template typename t class singleton boost noncopyable static void init private static pthread once t ponce statict value template typena...

C 單例模式

效率有點低,但是還算安全的單例模式,靜態成員實現方式 class singleton public static singleton getinstance singleton singleton getinstance unlock return m instance 內部靜態例項的懶漢模式,c ...