C/C++——跟我重寫智慧指標auto_ptr模版類

readyao發表於2016-05-10

第一次使用auto_ptr的時候感覺很好用,但是對內部原理根本不懂,心裡不知道這東西到底是個什麼東東,總是感覺這東東比較陌生。今天有時間來簡單實現一下該類模版auto_ptr,實現了該模版類的主要功能,可以讓大家瞭解一下這個東東內部到底是個什麼情況。

棧物件和堆物件的區別:

首先,看一下兩種類物件的區別,一個是在棧上分配空間,另一個是在堆上分配空間。

如果看到這裡,你不清楚堆和棧的區別。那我也不解釋了,自行Google..(如果你想baidu也不攔你)

1、先測試棧上分配的物件

#include <iostream>
#include <memory>
using namespace std;


/****************************************
*   類名稱:A(用於測試的類)
****************************************/
class A
{
public:
    A(int num):a(num){cout << "A(int num)" << endl;}
    A(){cout << "A()" << endl;}
    ~A(){cout << "~A()" << endl;}

    void func(){
        cout << "A.fun()" << endl;
    }

private:
    int a;
};


/****************************************
*  主測試函式main 
****************************************/
int main()
{
    A a1;
    a1.func();

    //A * pa = new A();
    //pa->func();

    return 0;
}

程式輸出為:

A()
A.fun()
~A()

從輸出結果可以看出,在棧上分配的物件在離開作用域的時候會自動呼叫解構函式,不用手動釋放。


2、再測試堆上分配的物件

將上面的main函式改為下面:

/****************************************
*  主測試函式main 
****************************************/
int main()
{
    //A a1;
    //a1.func();

    A * pa = new A();
    pa->func();

    return 0;
}

程式輸出為:

A()
A.fun()

從輸出結果可以看出,在堆上分配的物件在離開作用域的時候不會自動呼叫解構函式,需要手動釋放。

下面是新增手動釋放物件的語句:

/****************************************
*  主測試函式main 
****************************************/
int main()
{
    //A a1;
    //a1.func();

    A * pa = new A();
    pa->func();
    delete pa;

    return 0;
}

下面是改了之後的程式輸出:

A()
A.fun()
~A()

為什麼需要智慧指標?

從上面的例子可以看出,對於在堆上分配的物件的釋放是一件比較麻煩的事情,如果忘了手動釋放,那就會造成記憶體的洩漏。如果全部收到釋放,那麼又給程式設計師帶來很大的麻煩。

那麼就想啊,有什麼辦法可以像棧物件那樣操作堆物件。棧物件是在棧記憶體空間的物件,當物件超過作用域的時候會自動釋放。那麼我們可以讓棧記憶體空間上的一個指標物件專門來管理堆物件,當指標物件離開作用域的時候肯定會呼叫自身的解構函式,那麼我們在指標物件的解構函式中對它管理的堆物件記憶體空間進行釋放。


智慧指標auto_ptr簡單應用例項:

#include <iostream>
#include <memory>
using namespace std;

/****************************************
*   類名稱:A(用於測試的類)
****************************************/
class A
{
public:
    A(int num):a(num){cout << "A(int num)" << endl;}
    A(){cout << "A()" << endl;}
    ~A(){cout << "~A()" << endl;}

    void func(){
        cout << "A.fun()" << endl;
    }

private:
    int a;
};

/****************************************
*  主測試函式main 
****************************************/
int main()
{
    //使用智慧指標模版類auto_ptr
    //new A等價於new A(),但是如果有括號的話,可以呼叫帶參的建構函式,如new A(10);
    auto_ptr<A> ptr(new A);
    ptr->func();
    (*ptr).func();

    return 0;
}

程式輸出為:

A()
A.fun()
A.fun()
~A()

在上面的例子中可以看出,auto_ptr是一個模版類,我們在這裡定義了一個管理類A物件的一個指標物件ptr,該指標物件ptr可以使用運算子->和*,所以在類auto_ptr中過載了運算子->和*。

在上面例子中的指標物件ptr是棧物件,在離開作用域的時候會自動釋放,然後會自動呼叫解構函式,在它的解構函式中會釋放它指向的堆物件,從而達到了智慧指標的效果。


重寫智慧指標模版類SmartPointer:

/****************************************
*   類名稱:Smart智慧指標模版類
****************************************/

template<typename T>
class SmartPointer
{
public:
    //建構函式
    SmartPointer(T * p = NULL):ptr(p){

    }

    //解構函式
    ~SmartPointer(){
        if(ptr != NULL)
            delete ptr;
    }

    //過載->運算子
    T * operator->(){
        return ptr;
    }

    //過載*運算子
    T & operator*(){
        return *ptr;
    }
private:
    T * ptr;
};

在程式中可以看出,該模版類過載了運算子->和*,並實現了管理堆物件的功能。


下面是測試智慧指標模版類SmartPointer:

/*************************************************************************
	> File Name: smartPointerTemplate.cpp
	> Author: 
	> Mail: 
	> Created Time: 2016年05月10日 星期二 19時26分14秒
 ************************************************************************/

#include <iostream>
using namespace std;


/****************************************
*   類名稱:A(用於測試的類)
****************************************/
class A
{
public:
    A(int num):a(num){cout << "A(int num)" << endl;}
    A(){cout << "A()" << endl;}
    ~A(){cout << "~A()" << endl;}

    void func(){
        cout << "A::fun()" << endl;
    }

private:
    int a;
};

/****************************************
*   類名稱:B(用於測試的類)
****************************************/
class B
{
public:
    B(){cout << "B()" << endl;}
    ~B(){cout << "~B()" << endl;}

    void func(){
        cout << "B::func()" << endl;
    }

};


/****************************************
*   類名稱:Smart智慧指標模版類
****************************************/

template<typename T>
class SmartPointer
{
public:
    //建構函式
    SmartPointer(T * p = NULL):ptr(p){

    }

    //解構函式
    ~SmartPointer(){
        if(ptr != NULL)
            delete ptr;
    }

    //過載->運算子
    T * operator->(){
        return ptr;
    }

    //過載*運算子
    T & operator*(){
        return *ptr;
    }
private:
    T * ptr;
};


/****************************************
*  主測試函式main 
****************************************/
int main()
{
    SmartPointer<A> smt(new A());
    smt->func();
    (*smt).func();

    SmartPointer<B> smtB(new B());
    smtB->func();
    (*smtB).func();

    return 0;
}

下面是程式的輸出結果:

A()
A::fun()
A::fun()
B()
B::func()
B::func()
~B()
~A()

從輸出結果可以看出該模版類智慧指標也實現了管理堆物件的功能。


相關文章