您好,登錄后才能下訂單哦!
本篇文章為大家展示了詳解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; }
代碼的本意:靜態成員函數getInstance獲取單例指針,并且在析構函數中做一些收尾工作。
運行代碼后發現析構函數死活不執行,難道一個單例模式都能寫錯?反復確認,沒發現問題所在,于是上萬能的StackOverflow上找原因。正好有伙計有同樣的疑惑,有哥們給出了一個可行的方案。根據其答案修改代碼如下:
namespace tlanyan { class Foo { private: Foo() {} // other members public: static Foo& getInstance() { static Foo _instance; return _instance; } ~Foo() { // clean codes } // other members and codes }; }
對比前一段代碼,主要改動是移除了靜態指針成員,改用函數內的靜態成員。由于_instance是函數內的靜態成員,在首次調用時被初始化(感謝無參構造函數),之后調用將略過初始化而執行后續代碼;函數返回實例的引用,故而每次調用得到的是同一個對象,達到了單例的目的;程序執行結束后,實例的析構函數被自動調用,析構函數中的代碼正確執行。
問題解決了,但什么原因造成第一段單例代碼的析構函數不執行呢?
這是由于C++持有對象的方式造成的(或者說C++允許程序員手動控制內存引起)。Java/PHP等帶有回收機制的語言,持有對象的方式是通過指針,程序員申請對象后會自動分配內存,系統負責跟蹤和回收無用的對象和存在。C++允許開發人員以變量的方式持有對象,例如:Foo foo [= Foo(args)]
。變量初始化后獲得對象的引用,離開作用域后,系統銷毀執行棧,對象自動被析構。C++也可以以指針的形式獲得對象的引用: Foo* foo = new Foo(args)
。這種方式分配的對象,需要開發人員手動管理。如果不執行delete,對象和分配的內存將一直存在,直到程序退出后,才由操作系統回收。如下代碼可說明這點:
namespace tlanyan { void foo() { Foo foo; // 聲明變量,編譯器會自動初始化變量 Foo* ptr = new Foo(); // 聲明對象指針,同時為對象開辟內存 // awesome codes return; // 離開作用域, foo對象將被自動析構;如果之前沒有調用過delete ptr, ptr指向的對象將一直存在;如果delete ptr,析構函數將被執行。也可以將ptr指向的對象賦值給外層作用域的指針,此時有多個指針指向同一個變量 } }
從上面的代碼可以看出,對象沒有引用計數的情況下,編譯器和系統不敢隨便回收new出來的對象內存:多個指針指向同一個對象,delete了對象可能會導致其他代碼崩潰;釋放內存后,其他指針再delete會多次delete同一塊內存,引發不可預知風險。
綜上,指針單例析構函數沒有被調用的原因是: 自己new的對象,需要自己delete,別指望別人幫你正確調用析構函數。
問題的解決方案有以下幾種:
上述內容就是詳解C++中的單例,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。