昨天寫了個單例模式,當時感覺有個問題:
new出來的對象一直沒有釋放!這不是記憶體泄露嗎?
後來就看了別人的代碼,java中是沒有的,因為不需要。又看了一份c++的,也沒有。我就想,可能不需要吧,在程式運行期間,最多隻有一個instance,不會耗盡記憶體的,最多O(1)的記憶體。
可是今天怎麼考慮覺得這種解釋太牽強了!如果對象很大呢?如果有很多類的單例instance呢?
於是又繼續查,發現很多人都沒有寫解構函式,但是有些還是有的。
所以,解構函式還是需要的。一個完美的代碼是不能有潛在bug的。
既然需要一個解構函式,那麼在哪裡調用呢?在程式結束後手動調用?顯然這樣不好。因為我們不知道什麼時候不再需要這個對象。
再網上看到別人一個巧妙的解決方案:
使用一個內部類負責析構。感覺有點像代理模式了?
因為任何靜態對象在程式運行期間都存在,生命期結束後都會被收回。所以可以讓這個靜態對象析構的時候析構這個單例對象。
其實還有另外一個問題,很大的bug:
雖然定義了protected的建構函式,但是仍然不能保證只有一個instance,因為還有拷貝建構函式和賦值建構函式,調用的話編譯器會合成。。。
改進後的代碼:
#include <iostream>using namespace std;class Singleton{protected: Singleton() {cout<<"con of Singleton"<<endl;} ~Singleton(){cout<<"dcon of Singleton"<<endl;} Singleton(const Singleton& s);///只定義,不實現public: static Singleton * getInstance() { if(_instance==0) { _instance = new Singleton(); } return _instance; } ///other class functions... void show() { cout<<"This is a Singleton !"<<endl; }private: static Singleton * _instance; ///other class members ... class Proxy { public: ~Proxy() { if(_instance!=0) { delete _instance; _instance = 0; } } }; static Proxy pt;};///靜態成員的初始化Singleton* Singleton::_instance = 0;//new Singleton();Singleton::Proxy Singleton::pt;int main(){ Singleton *s=Singleton::getInstance(); s->show(); Singleton *a=Singleton::getInstance(); a->show(); cout<<(a == s)<<endl; //Singleton b; ///compile error! //Singleton c(*s);///compile error! //Singleton d=*a;///compile error! return 0;}
暫時應該是沒問題了。
考慮最佳化,如果在程式中大量調用getInstance(),除了第一次判斷成功外,其他情況下這段代碼
if(_instance==0) { _instance = new Singleton(); }
顯得很多餘!
可以在初始化時就建立一個對象:
Singleton* Singleton::_instance = new Singleton();
然後把上面的if 程式碼片段刪除,就可以了。
如果不是返回指標,使用引用即可:
#include <iostream>using namespace std;class Singleton{protected: Singleton() {cout<<"con of Singleton"<<endl;} ~Singleton(){cout<<"dcon of Singleton"<<endl;} Singleton(const Singleton& s);///只定義,不實現public: static Singleton & getInstance() { return _instance; } ///other class functions... void show() { cout<<"This is a Singleton !"<<endl; }private: static Singleton & _instance; ///other class members ... class Proxy { public: ~Proxy() { _instance.~Singleton(); } }; static Proxy pt;};///靜態成員的初始化Singleton& Singleton::_instance = *(new Singleton());Singleton::Proxy Singleton::pt;int main(){ Singleton &s=Singleton::getInstance(); s.show(); Singleton &a=Singleton::getInstance(); a.show(); cout<<(&s==&a)<<endl; return 0;}