成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

C++之單例的幾種寫法

開發
單例可以說是眾多設計模式中最常用的了,同時單例設計模式也是一個老生常談的問題,這是因為寫一個單例卻是很簡單,但是想要寫好一個單例卻比較難。

單例可以說是眾多設計模式中最常用的了,同時單例設計模式也是一個老生常談的問題,這是因為寫一個單例卻是很簡單,但是想要寫好一個單例卻比較難。

首先我們先來理一下在C++中實現單例最基本的幾個步驟:

  • 私有化構造函數、拷貝構造函數、賦值運算符等;
  • 確保線程安全;
  • static靜態變量只初始化一次;

單例的幾種模式

1.最簡單的餓漢模式

#include <iostream>

class Singleton {
private:
    // 聲明
    static Singleton* instance;
    int a{0};
    Singleton() {
        std::cout << "Singleton 構造函數" << std::endl;
    }
    Singleton(const Singleton& temp) {
        std::cout << "Singleton 拷貝構造函數" << std::endl;
    }
    Singleton& operator = (const Singleton& temp){
        return *instance;
    }

public:
    static Singleton* getInstance() {
        return instance;
    }

    void addA(){
        a++;
    }

    void printA(){
        std::cout << "printA:" << a << std::endl;
    }
};

// 類靜態變量要在類內聲明,類外定義
Singleton *Singleton::instance = new Singleton;

int main() {
    Singleton* singleton = Singleton::getInstance();
    singleton->addA();
    singleton->printA();
    return 0;
}

這種寫法常用,但是也藏了一些隱患,比如如果使用者自作聰明在通過函數getInstance獲取到了單例指針,使用完畢后調用delete刪除了指針那怎么辦? 請問作為"資深"的復制粘貼工程師你知道怎么避免這種情況嗎?

一把情況下我們如果不希望開發者調用delete刪除指針,可以直接重載delete函數,并且將其設置偉私有方法,或者在C++11以上我們直接使用delete關鍵字將delete函數禁用掉。

上面的代碼例子是指針形式的單例,當然你也可以試試非指針式的單例書寫,其實更推薦非指針式的單例。

2.加鎖的餓漢模式

#include <iostream>
#include <mutex>

class Singleton {
private:
    int a{0};
    // 聲明
    static std::mutex mtx;
    static Singleton* instance;
    Singleton(){

    }
    Singleton(const Singleton& temp) {
        std::cout << "Singleton 拷貝構造函數" << std::endl;
    }
    Singleton& operator=(const Singleton& temp){
        return *instance;
    }
public:
    static Singleton* getInstance() {
        // 鎖、雙重判斷
        if(nullptr == instance){
            mtx.lock();
            if (nullptr == instance) {
                instance = new Singleton();
            }
            mtx.unlock();
        }
        return instance;
    }

    void addA(){
        a++;
    }

    void printA(){
        std::cout << "printA:" << a << std::endl;
    }
};

// 需要定義
std::mutex Singleton::mtx;
Singleton *Singleton::instance{nullptr};

int main() {
    Singleton* singleton = Singleton::getInstance();
    singleton->addA();
    singleton->printA();
    return 0;
}

想用懶加載模式,同時為了保證線程安全,以上代碼是很多童鞋會寫出的示例代碼,然而在C++上述代碼卻并不能一定保證正確。

這是因為程序在執行的過程中,出于效率的考量,兩個(在當前線程中)沒有依賴的指令可能會調換順序執行也就是 CPU 動態調度。對于 CPU 來說,這已經是幾十年的老技術了, 這里就不多說了。

因此以上這個鎖加雙重判斷的懶漢模式既繁瑣又不安全,并不推薦。

3.C++11之后新特性std::call_once的模式

在單例的實現中,我們實際上是希望實現「執行且只執行一次」的語義。這在 C++11 之后,標準庫實際已經提供了這樣的實現。 那就是std::once_flag和std::call_once。它們內部利用互斥量和條件變量組合,實現了「執行且只執行一次」這樣的語義。

下面我們看看使用std::once_flag和std::call_once實現的單例代碼實例:

#include <iostream>
#include <mutex>

class Singleton {
private:
    int a{0};
    // 聲明
    static std::once_flag flag;
    static Singleton* instance;
    Singleton(){
        std::cout << "Singleton 構造函數" << std::endl;
    }
    Singleton(const Singleton& temp) {
        std::cout << "Singleton 拷貝構造函數" << std::endl;
    }
    Singleton& operator=(const Singleton& temp){
        return *instance;
    }
public:
    static Singleton* getInstance() {
        std::call_once(flag, [&]() -> void {
            instance = new Singleton;
        });
        return instance;
    }

    void addA(){
        a++;
    }

    void printA(){
        std::cout << "printA:" << a << std::endl;
    }
};

// 需要定義
std::once_flag Singleton::flag;
Singleton *Singleton::instance{nullptr};

int main() {
    Singleton* singleton = Singleton::getInstance();
    singleton->addA();
    singleton->printA();
    Singleton::getInstance()->addA();
    Singleton::getInstance()->printA();
    return 0;
}

實例代碼運行結果:

需要注意的是,所有的 std::once_flag 內部共享了同一對互斥量和條件變量。因此當存在很多 std::call_once 的時候,性能會有所下降。 但是從另外一個角度想想如果一個程序中存在很多的std::call_once,那么這個程序本身就設計得很不合理,這種情況更應該從程序設計的源頭上避免。

4.函數內static變量的模式

在 C++11 之后,C++標準保證函數靜態成員的初始化是線程安全的,對其讀寫則不保證線程安全。既然如此,那么我在直接在函數內部使用static 修飾一個單例變量不就好了么?

精簡一下代碼如下:

#include <iostream>

class Singleton {
private:
    int a{0};
    Singleton(){
        std::cout << "Singleton 構造函數" << std::endl;
    }
    Singleton(const Singleton& temp) {
        std::cout << "Singleton 拷貝構造函數" << std::endl;
    }
    Singleton& operator=(const Singleton& temp){
        return *this;
    }
public:
    static Singleton* getInstance() {
        static Singleton instance;
        return &instance;
    }

    void addA(){
        a++;
    }

    void printA(){
        std::cout << "printA:" << a << std::endl;
    }
};

int main() {
    Singleton* singleton = Singleton::getInstance();
    singleton->addA();
    singleton->printA();
    Singleton::getInstance()->addA();
    Singleton::getInstance()->printA();
    return 0;
}

以上代碼實現的單例即是線程安全,同時也是懶加載的,這就是在C++11之后,Effective C++最推薦的單例模式寫法。

模版形式的單例

實現一個類模板,其模板參數是希望由單例管理的類的名字,并提供 getInstance 之類的靜態接口。這種做法的好處是希望被單例管理的類,可以自由編寫,而無需繼承基類;并且在需要的時候,可以隨時脫去單例外衣。

#include <iostream>

template <typename T>
struct Singleton {
    static T* getInstance() {
        static T ins;
        return &ins;
    }
};

class A{
private:
    int a{0};
    A(const A& tmp){
        std::cout << "A拷貝構造函數" << std::endl;
    }
    A& operator=(const A& tmp){
        std::cout << "A賦值運算符" << std::endl;
        return *this;
    }

public:
    A(){
        std::cout << "A構造函數" << std::endl;
    }
    void addA(){
        a++;
    }

    void printA(){
        std::cout << "printA:" << a << std::endl;
    }
};

int main() {
    A* singleton = Singleton<A>::getInstance();
    singleton->addA();
    singleton->printA();
    A* singleton1 = Singleton<A>::getInstance();
    singleton1->addA();
    singleton1->printA();
    return 0;
}

由上面的代碼可以看出,單例管理就交給了模版Singleton去控制了,類A本身就不知乎嚴格控制自己是否是單例了,這種實現就比較的靈活,如果你想使用單例的類A就搭配Singleton的模版進行使用即可, 如果你想使用非單例的類A就像正常那樣使用即可。

責任編輯:趙寧寧 來源: 思想覺悟
相關推薦

2022-05-23 07:35:15

單例模式懶漢模式靜態內部類

2015-09-06 11:07:52

C++設計模式單例模式

2010-02-05 17:00:06

C++單例模式

2024-12-03 16:49:58

2010-02-03 09:43:16

C++單例模式

2022-08-10 11:02:56

Python單例模式

2023-03-21 15:21:52

開發程序設計static

2010-01-27 10:45:21

C++單例模式

2012-02-02 10:21:05

單鏈表nexthead

2021-09-07 10:44:35

異步單例模式

2010-02-06 11:13:11

C++ makefil

2010-01-22 14:46:25

C++語言

2021-06-10 09:00:33

單例模式數據庫

2013-03-26 10:35:47

Objective-C單例實現

2016-03-28 10:23:11

Android設計單例

2011-07-15 00:47:13

C++多態

2010-02-06 14:12:54

C++繼承方式

2011-07-14 17:45:06

CC++

2011-07-13 18:24:18

C++

2022-06-07 08:55:04

Golang單例模式語言
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91免费福利视频 | 成人欧美一区二区三区在线播放 | 欧美mv日韩mv国产网站91进入 | av一级| 欧美一级在线观看 | 欧美日韩在线一区二区三区 | 亚洲视频免费在线播放 | 亚洲精品久久久久久久不卡四虎 | 欧美八区 | 久久一视频 | 成人欧美一区二区三区色青冈 | 国产视频二区 | 欧美日韩手机在线观看 | 干干干操操操 | 日韩精品一区二区三区高清免费 | 国产欧美精品一区二区 | 成人99| 亚洲人成人网 | 午夜精品久久久久久久久久久久久 | 夜夜干夜夜操 | 免费a大片 | 亚洲午夜网 | 久久久久久久久中文字幕 | 亚洲精品自在在线观看 | 国产精品一区二区视频 | 精品久久一区 | 在线播放国产一区二区三区 | 91在线中文字幕 | 日日夜夜天天 | 午夜精品久久久久久久99黑人 | 欧美理论片在线 | 久久综合色综合 | 精品日韩欧美一区二区 | 亚州影院| 免费毛片网站在线观看 | 精品免费国产一区二区三区四区介绍 | 国产一区二区在线观看视频 | 国产精品久久久久久久久久免费看 | 国产精品美女久久久久久免费 | 精品无码久久久久久久动漫 | 欧美亚洲国产日韩 |