單例模式及其析構
阿新 • • 發佈:2018-11-03
#include <cstddef> class Single { public: ~Single() {} static Single* instance() { if (ptr == NULL) { ptr = new Single; } return ptr; } void destory() { if (ptr != NULL) { delete ptr; ptr = NULL; } } int getVal() const { return i; } private: // constructor Single() { i = 0; } // copy constructor Single(Single&); // assignment constructor Single& operator = (const Single&); // members static Single* ptr; int i; }; int main() { int val = Single::instance()->getVal(); Single::instance()->destory(); mySingle = NULL; return 0; }
使用完該單例後,需要釋放記憶體的時候必須注意:
1、不要直接使用類的解構函式來釋放,否則將引起無休止的迴圈!
將解構函式改成如下形式,然後用解構函式來釋放
Single::~Single() { if (ptr != NULL) { delete ptr; ptr = NULL; } } Single* mySinglePtr = Single::instance(); delete mySinglePtr;
首先 delete mySinglePtr;會呼叫Single的解構函式,在解構函式內,進行指標判斷,如果不為空,則delete ptr,而ptr所指的物件是Single,則再去呼叫解構函式,以此往復,形成死迴圈。
2、正確方法:另提供一個釋放的介面,由這個單例的使用者來釋放。
示例程式中,提供了destory的介面,使用者需要釋放記憶體,則呼叫改介面。
3、很容易犯的一個錯誤:(類的定義是示例程式中的,即不呼叫解構函式,而是用destory來釋放記憶體)
// 使用者1 Single* mySinglePtr = Single::instance(); delete mySinglePtr; mySinglePtr = NULL; // 使用者2在使用者1delete後,使用instance Singel* mySinglePtr2 = Single::instance(); mySinglePtr2->getVal(); // ****此時,出現segment default!!!
原因:使用者1delete mySinglePtr後,將Single的例項已經釋放掉,但是但是!!Single中的ptr沒有復位為空指標!!!!仍然指向之前new出來的記憶體(但這塊記憶體已經被delete掉,系統已經回收)。使用者2要使用instance,Single::instance()判斷此時的ptr不為空,就直接返回了ptr指標,ptr指向了已經被系統回收的記憶體,造成segment default。