1. 程式人生 > >單例模式及其析構

單例模式及其析構

#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。