公司編輯UI有個編輯器,是個MFC框架的窗口。長時間以來,每次點關閉按鈕關閉的時候都會報windows的調試,從而再啓動一次。ios
平時你們工做都是趕任務,這個問題一直能忍則忍。後來這個問題致使我其餘vs解決方案連接的時候總是失敗。c++
因爲這個編輯器會引用到另外一個項目的lib,若是編輯器不能正常關閉,那麼另外一個項目連接的時候就會報沒法打開某個lib。windows
因而我就想着怎麼解決編輯器不能正常關閉的問題。框架
編輯器有源碼,是MFC框架的。因而我首先簡單找了一本侯捷的《深刻淺出MFC》看了一下MFC的關閉流程。發現沒有什麼特別的地方。編輯器
爲了保持環境乾淨,我從新clone了一份編輯器的代碼,再從新生成。偶然發現每次關閉以後,工做目錄下都會有個文件的修改時間變成新的。函數
難道有內存泄漏?並且咱們的代碼裏有內存追蹤模塊?spa
打開文件看了以後,確認應該是有內存泄漏。並且每次幾乎是同樣的,泄漏的地方相同。這可能就好找了。3d
不過我好奇怎麼作的內存追蹤,因而我讀了一下咱們引擎裏的內存追蹤模塊。這塊另寫一篇來說。指針
這裏講一個單例模式的內存泄漏。還有怎麼寫能不內存泄漏。調試
直接看一下簡化後的代碼:
1 class Singleton 2 { 3 public: 4 static Singleton* Instance(); 5 Singleton() = default; 6 ~Singleton() = delete; 7 8 int mem = 1; 9 10 void printInstance() { cout << "print Instance" << endl; } 11 }; 12 13 Singleton * Singleton::Instance() 14 { 15 static Singleton* instance = new Singleton; 16 return instance; 17 }
1 int main() 2 { 3 Singleton::Instance()->printInstance(); 4 Singleton::Instance()->printInstance(); 5 6 return 0; 7 }
運行結果:
注意到幾點:1.析構函數=delete。2.Instance()裏有一個static的Singleton*,有new操做,可是沒有對應的delete操做。
1.析構函數=delete。
這個c++11的新寫法。表明該函數爲刪除函數,也就是不能重載,不會被調用。這類函數能夠聲明,可是沒有定義。編譯器會阻止對它們進行定義。
相似的若是想要阻止拷貝,阻止賦值拷貝,也能夠把拷貝構造函數和賦值拷貝構造函數聲明爲刪除函數。
Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete;
可是這裏把析構函數聲明爲刪除函數??這樣就阻止了對象的析構了。
在《c++ primer》第五版的13.1.5節裏有提到,析構函數不能是刪除函數。
這裏有什麼其餘的考量?不得而知。
2.static的Singleton*。
這裏是一個已初始化局部的static變量,咱們知道已初始話的static變量會放在.data區,並且會在程序結束的時候自動清理。
可是這裏是new出來的對象,因此程序結束的時候是不會清理的。
怎麼改比較好呢?
1.首先析構函數固然不能是刪除函數。
2.new出來的static對象指針在程序結束不會自動清理,可是static對象會自動析構。能夠利用這一點寫一個static自動清理的類對象。
1 #include <iostream> 2 3 using namespace std; 4 5 class Singleton 6 { 7 public: 8 Singleton() { cout << "Singleton Constructor " << endl; } 9 ~Singleton() { cout << "Singleton Destructor " << endl; } 10 11 static Singleton* Instance(); 12 static Singleton* m_instance; 13 14 int mem = 1; 15 16 void printInstance() { cout << "print Instance" << endl; } 17 18 class AutoRelease 19 { 20 public: 21 AutoRelease() { cout << "AutoRelease Constructor " << endl; } 22 23 ~AutoRelease() 24 { 25 if (m_instance != nullptr) 26 { 27 delete(m_instance); 28 m_instance = nullptr; 29 cout << "AutoRelease Destructor" << endl; 30 } 31 } 32 }; 33 }; 34 35 Singleton* Singleton::m_instance = nullptr; 36 37 Singleton * Singleton::Instance() 38 { 39 if (m_instance == nullptr) 40 { 41 m_instance = new Singleton; 42 static AutoRelease auto_release; 43 } 44 return m_instance; 45 } 46 47 int main() 48 { 49 Singleton::Instance()->printInstance(); 50 Singleton::Instance()->printInstance(); 51 52 return 0; 53 }
運行結果:
如此就能正常析構了。
如此思路重構了代碼,memeryleak裏面便少了這部分的內存泄漏記錄。