Day4:單例模式

單例模式:

單例是設(shè)計模式的一種,保證一個類只有一個實例,并提供一個可以訪問它的全局訪問點。
通??梢宰屢粋€全局變量使得一個對象被訪問,但是不能阻止實例化多個對象,解決辦法是:讓類自身負責保存它的唯一實例,這個類保證沒有其他的實例可以被創(chuàng)建,并且它提供一個可以訪問該實例的方法。
Singleton類中,定義一個getInstance()靜態(tài)成員函數(shù),允許用戶訪問它的唯一的實例,getInstance是一個靜態(tài)方法,主要負責創(chuàng)建自己的唯一實例。

//不安全的單例模式  存在線程安全和內(nèi)存泄漏
class Singleton1 { 
  private:
    Singleton1() { cout<< "Singleton1 Construct!"<<endl;}
    Singleton1(const Singleton1 &) = delete;
    Singleton1 & operator =(const Singleton1&) = delete;
    static Singleton1* resptr_1;
  public:
    ~Singleton1() {cout<< "Singleton1 Destruct"<<endl;}
    static Singleton1* getInstance();
    void func();
};

Singleton1* Singleton1::getInstance() {
    if (resptr_1 == nullptr) {
        resptr_1 = new Singleton1;
    }
    return resptr_1;
}

void Singleton1::func () {
    cout << "do something here!"<< endl;
}

客戶端代碼:

Singleton1* Singleton1::resptr_1 = nullptr;
int main() {
    Singleton1 * instance1 = Singleton1::getInstance();
    Singleton1 * instance2 = Singleton1::getInstance();
    instance1->func();
    instance2->func();
    if (instance1== instance2) 
        cout << "instance1 == instance2"<<endl;
    cout << endl;
    
    system("pause");
    return 0;
}
執(zhí)行結(jié)果

上述代碼有內(nèi)存泄漏的問題,以及再多線程情況下存在線程安全的情況,對于以上情況,可以使用雙檢鎖來解決線程安全的問題,使用智能指針托管創(chuàng)建的實例。如下類Singletion2實現(xiàn)

//shared_ptr 解決內(nèi)存泄漏,雙檢鎖解決線程安全
class Singleton2 {  
  private:
    Singleton2() { cout << "Singleton2 Construct!"<< endl;}
    static shared_ptr<Singleton2> resptr_2;
    static mutex mutex_;
    //void func();
  public:
    ~Singleton2() {cout<< "Singleton2 Destruct"<<endl;}
    Singleton2(const Singleton2&) = delete;
    Singleton2& operator =(const Singleton2&) = delete;
    static shared_ptr<Singleton2> getInstance();
    void func();
};

shared_ptr<Singleton2> Singleton2::getInstance() {
    if (resptr_2 == nullptr) {
        lock_guard<mutex> lk(mutex_);
        if (resptr_2 == nullptr) {
            resptr_2 = shared_ptr<Singleton2>(new Singleton2);
        }
    }
    return resptr_2;
}

void Singleton2::func() {
    cout << "do something here!"<< endl;
}

客戶端代碼:

shared_ptr<Singleton2> Singleton2::resptr_2 = nullptr;
mutex Singleton2::mutex_;
int main() {
    shared_ptr<Singleton2> instance3 = Singleton2::getInstance();
    shared_ptr<Singleton2> instance4 = Singleton2::getInstance();
    instance3->func();
    instance4->func();
    if (instance3 == instance4) 
        cout << "instance3 == instance4"<<endl;
    cout <<endl;
    system("pause");
    return 0;
}

image.png

C++11標準中的Magic Static特性:如果當變量在初始化的時候,并發(fā)同時進入聲明語句,并發(fā)線程將會阻塞等待初始化結(jié)束。利用該特性就可以寫出一根非常好的線程安全的單例模式代碼。如下Singleton3:

/局部靜態(tài)變量的方式。如果當變量在初始化的時候,并發(fā)同時進入聲明語句,并發(fā)線程將會阻塞等待初始化結(jié)束
class Singleton3 {
  private:
    Singleton3() {cout << "Singleton3 Construct!"<<endl;}
  public:
    ~Singleton3() {cout<< "Singleton3 Destruct"<<endl;}
    Singleton3(const Singleton3&) = delete;
    Singleton3& operator =(const Singleton3&) = delete;
    static Singleton3& getInstance();
    void func();
};

Singleton3& Singleton3::getInstance() {
    static Singleton3 instance;
    return instance;
}

void Singleton3::func() {
    cout << "do something here!"<<endl;
}

客戶端代碼:


int main() {
    Singleton3 & instance5 = Singleton3::getInstance();
    Singleton3 & instance6 = Singleton3::getInstance();
    instance5.func();
    instance6.func();
    if (&instance5 == &instance6) 
        cout << "instance5 == instance6"<<endl;

    system("pause");
    return 0;
}


image.png

人們又根據(jù)實例的創(chuàng)建時間將單例模式分為了懶漢式和餓漢式
餓漢式:類構(gòu)造的時候就創(chuàng)建實例對象,空間換時間的策略
懶漢式:需要的時候,創(chuàng)建實例,時間換空間的策略
很明顯上述的三款代碼都是懶漢式的單例模式,餓漢式的特點是線程安全的,因為在類產(chǎn)生的時候就已經(jīng)將實例創(chuàng)建了每次獲取的收直接返回的是預先創(chuàng)建好額實例,也就不存在創(chuàng)建多個的情況了,餓漢式的單例模式如下所示:

class Singleton { 
  private:
    Singleton() { cout<< "Singleton Construct!"<<endl;}
    Singleton(const Singleton &) = delete;
    Singleton & operator =(const Singleton&) = delete;
    static Singleton  instance;//創(chuàng)建實例。
  public:
    ~Singleton() {cout<< "Singleton Destruct"<<endl;}
    static Singleton* getInstance();
    void func();
};

Singleton*  Singleton::getInstance() {
    return &instance;
}

void Singleton::func () {
    cout << "do something here!"<< endl;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容