欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

談?wù)凜++中的單例

 更新時(shí)間:2020年09月11日 14:46:56   作者:tlanyan  
這篇文章主要介紹了C++中單例的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)c++,感興趣的朋友可以了解下

寫C++的時(shí)候用到單例,于是很自然的寫出如下的代碼:

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獲取單例指針,并且在析構(gòu)函數(shù)中做一些收尾工作。

運(yùn)行代碼后發(fā)現(xiàn)析構(gòu)函數(shù)死活不執(zhí)行,難道一個(gè)單例模式都能寫錯(cuò)?反復(fù)確認(rèn),沒(méi)發(fā)現(xiàn)問(wèn)題所在,于是上萬(wàn)能的StackOverflow上找原因。正好有伙計(jì)有同樣的疑惑,有哥們給出了一個(gè)可行的方案。根據(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
  };
}

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

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

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

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

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

綜上,指針單例析構(gòu)函數(shù)沒(méi)有被調(diào)用的原因是: 自己new的對(duì)象,需要自己delete,別指望別人幫你正確調(diào)用析構(gòu)函數(shù)。

問(wèn)題的解決方案有以下幾種:

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

如有其它解決方案,歡迎交流指正!

以上就是談?wù)凜++中的單例的詳細(xì)內(nèi)容,更多關(guān)于c++ 單例的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論