溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

詳解C++中的單例

發(fā)布時間:2020-11-03 16:48:35 來源:億速云 閱讀:135 作者:Leah 欄目:開發(fā)技術

本篇文章為大家展示了詳解C++中的單例,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

namespace tlanyan {
  class Foo {
  private:
    static Foo* _instance;
    Foo() {}
    // other members

  public:
    static Foo* getInstance() {
      if (_instance == NULL) {
        _instance = new Foo();
      }
      return _instance;
    }
    ~Foo() {
      // clean codes
    }
    // other members and codes
  };
  Foo* Foo::_instance = NULL;
}

代碼的本意:靜態(tài)成員函數(shù)getInstance獲取單例指針,并且在析構函數(shù)中做一些收尾工作。

運行代碼后發(fā)現(xiàn)析構函數(shù)死活不執(zhí)行,難道一個單例模式都能寫錯?反復確認,沒發(fā)現(xiàn)問題所在,于是上萬能的StackOverflow上找原因。正好有伙計有同樣的疑惑,有哥們給出了一個可行的方案。根據(jù)其答案修改代碼如下:

namespace tlanyan {
  class Foo {
  private:
    Foo() {}
    // other members

  public:
    static Foo& getInstance() {
      static Foo _instance;
      return _instance;
    }
    ~Foo() {
      // clean codes
    }
    // other members and codes
  };
}

對比前一段代碼,主要改動是移除了靜態(tài)指針成員,改用函數(shù)內的靜態(tài)成員。由于_instance是函數(shù)內的靜態(tài)成員,在首次調用時被初始化(感謝無參構造函數(shù)),之后調用將略過初始化而執(zhí)行后續(xù)代碼;函數(shù)返回實例的引用,故而每次調用得到的是同一個對象,達到了單例的目的;程序執(zhí)行結束后,實例的析構函數(shù)被自動調用,析構函數(shù)中的代碼正確執(zhí)行。

問題解決了,但什么原因造成第一段單例代碼的析構函數(shù)不執(zhí)行呢?

這是由于C++持有對象的方式造成的(或者說C++允許程序員手動控制內存引起)。Java/PHP等帶有回收機制的語言,持有對象的方式是通過指針,程序員申請對象后會自動分配內存,系統(tǒng)負責跟蹤和回收無用的對象和存在。C++允許開發(fā)人員以變量的方式持有對象,例如:Foo foo [= Foo(args)]。變量初始化后獲得對象的引用,離開作用域后,系統(tǒng)銷毀執(zhí)行棧,對象自動被析構。C++也可以以指針的形式獲得對象的引用: Foo* foo = new Foo(args)。這種方式分配的對象,需要開發(fā)人員手動管理。如果不執(zhí)行delete,對象和分配的內存將一直存在,直到程序退出后,才由操作系統(tǒng)回收。如下代碼可說明這點:

namespace tlanyan {
  void foo() {
    Foo foo;  // 聲明變量,編譯器會自動初始化變量
    Foo* ptr = new Foo();  // 聲明對象指針,同時為對象開辟內存
    // awesome codes
    return;    // 離開作用域, foo對象將被自動析構;如果之前沒有調用過delete ptr, ptr指向的對象將一直存在;如果delete ptr,析構函數(shù)將被執(zhí)行。也可以將ptr指向的對象賦值給外層作用域的指針,此時有多個指針指向同一個變量
  }
}

從上面的代碼可以看出,對象沒有引用計數(shù)的情況下,編譯器和系統(tǒng)不敢隨便回收new出來的對象內存:多個指針指向同一個對象,delete了對象可能會導致其他代碼崩潰;釋放內存后,其他指針再delete會多次delete同一塊內存,引發(fā)不可預知風險。

綜上,指針單例析構函數(shù)沒有被調用的原因是: 自己new的對象,需要自己delete,別指望別人幫你正確調用析構函數(shù)。

問題的解決方案有以下幾種:

  1. 同StackOverflow上回答,改用變量方式持有單例對象。程序運行結束前會銷毀所有變量,變量的析構函數(shù)將被正確調用;
  2. 在main函數(shù)退出前delete單例。例如增加一個destroy的靜態(tài)成員函數(shù),將指針指向的對象銷毀;
  3. 使用auto_ptr/unique_ptr等智能指針。

上述內容就是詳解C++中的單例,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

AI