1. 程式人生 > >資料結構開發(8):再論智慧指標

資料結構開發(8):再論智慧指標

0.目錄

1.Pointer與SmartPointer

2.SharedPointer

3.小結

1.Pointer與SmartPointer

本節目標:

  • 完成 Pointer 類的具體實現
  • 完成 SmartPointer 類的具體實現

思考

  • 使用智慧指標( SmartPointer )替換單鏈表( LinkList )中的原生指標是否可行?

問題出在哪裡?

  • SmartPointer的設計方案
    1. 指標生命週期結束時主動釋放堆空間
    2. 一片堆空間最多隻能由一個指標標識
    3. 杜絕指標運算和指標比較

新的設計方案——是時候建立新的智慧指標了!

Pointer是智慧指標的抽象父類( 模板 ):

  • 純虛解構函式 virtual ~Pointer() = 0;
  • 過載 operator-> ()
  • 過載 operator* ()

(在StLib中實現Pointer.h和SmartPointer.h)
Pointer.h

#ifndef POINTER_H
#define POINTER_H

#include "Object.h"

namespace StLib
{

template <typename T>
class Pointer : public Object
{
protected:
    T* m_pointer;
public:
    Pointer(T* p = NULL)
    {
        m_pointer = p;
    }

    T* operator-> ()
    {
        return m_pointer;
    }

    T& operator* ()
    {
        return *m_pointer;
    }

    bool isNull()
    {
        return (m_pointer == NULL);
    }

    T* get()
    {
        return m_pointer;
    }
};

}

#endif // POINTER_H

SmartPointer.h

#ifndef SMARTPOINTER_H
#define SMARTPOINTER_H

#include "Pointer.h"

namespace StLib
{

template <typename T>
class SmartPointer : public Pointer<T>
{
public:
    SmartPointer(T* p = NULL) : Pointer<T>(p)
    {
    }

    SmartPointer(const SmartPointer<T>& obj)
    {
        this->m_pointer = obj.m_pointer;

        const_cast<SmartPointer<T>&>(obj).m_pointer = NULL;
    }

    SmartPointer<T>& operator= (const SmartPointer<T>& obj)
    {
        if( this != &obj )
        {
            T* p = this->m_pointer;

            this->m_pointer = obj.m_pointer;

            const_cast<SmartPointer<T>&>(obj).m_pointer = NULL;

            delete p;
        }

        return *this;
    }

    ~SmartPointer()
    {
        delete this->m_pointer;
    }
};

}

#endif // SMARTPOINTER_H

main.cpp測試

#include <iostream>
#include "SmartPointer.h"

using namespace std;
using namespace StLib;

class Test : public Object
{
public:
    Test()
    {
        cout << "Test()" << endl;
    }
    ~Test()
    {
        cout << "~Test()" << endl;
    }
};

int main()
{
    SmartPointer<Test> sp = new Test();
    SmartPointer<Test> spn;

    spn = sp;

    return 0;
}

執行結果為:

Test()
~Test()

2.SharedPointer

思考:

  • 如何實現 SharedPointer 使得多個智慧指標物件可以指向同一片堆記憶體,同時支援堆記憶體的自動釋放?

本節目標:

  • 完成 SharedPointer 類的具體實現

SharedPointer 設計要點:

  • 類模板
    1. 通過計數機制( ref )標識堆記憶體
      1. 堆記憶體被指向時:ref++
      2. 指標被置空時:ref--
      3. ref == 0 時:釋放堆記憶體

計數機制原理剖析:

SharedPointer 類的宣告:

智慧指標的比較:

  • 由於 SharedPointer 支援多個物件同時指向一片堆空間;因此,必須支援比較操作

(在StLib中實現SharedPointer.h)
改進Pointer.h

#ifndef POINTER_H
#define POINTER_H

#include "Object.h"

namespace StLib
{

template <typename T>
class Pointer : public Object
{
protected:
    T* m_pointer;
public:
    Pointer(T* p = NULL)
    {
        m_pointer = p;
    }

    T* operator-> ()
    {
        return m_pointer;
    }

    T& operator* ()
    {
        return *m_pointer;
    }

    const T* operator-> () const
    {
        return m_pointer;
    }

    const T& operator* () const
    {
        return *m_pointer;
    }

    bool isNull() const
    {
        return (m_pointer == NULL);
    }

    T* get() const
    {
        return m_pointer;
    }
};

}

#endif // POINTER_H

SharedPointer.h

#ifndef SHAREDPOINTER_H
#define SHAREDPOINTER_H

#include <cstdlib>
#include "Pointer.h"
#include "Exception.h"

namespace StLib
{

template <typename T>
class SharedPointer : public Pointer<T>
{
protected:
    int* m_ref; // 計數機制成員指標

    void assign(const SharedPointer<T>& obj)
    {
        this->m_ref = obj.m_ref;
        this->m_pointer = obj.m_pointer;

        if( this->m_ref )
        {
            (*this->m_ref)++;
        }
    }
public:
    SharedPointer(T* p = NULL) : m_ref(NULL)
    {
        if( p )
        {
            this->m_ref = static_cast<int*>((std::malloc(sizeof(int))));

            if( this->m_ref )
            {
                *(this->m_ref) = 1;
                this->m_pointer = p;
            }
            else
            {
                THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create SharedPointer object ...");
            }
        }
    }

    SharedPointer(const SharedPointer<T>& obj) : Pointer<T>(NULL)
    {
        assign(obj);
    }

    SharedPointer<T>& operator= (const SharedPointer<T>& obj)
    {
        if( this != &obj )
        {
            clear();
            assign(obj);
        }

        return *this;
    }

    void clear() // 將當前指標置為空
    {
        T* toDel = this->m_pointer;
        int* ref = this->m_ref;

        this->m_pointer = NULL;
        this->m_ref = NULL;

        if( ref )
        {
            (*ref)--;

            if( *ref == 0 )
            {
                free(ref);

                delete toDel;
            }
        }
    }

    ~SharedPointer()
    {
        clear();
    }
};

template <typename T>
bool operator == (const SharedPointer<T>& l, const SharedPointer<T>& r)
{
    return (l.get() == r.get());
}

template <typename T>
bool operator != (const SharedPointer<T>& l, const SharedPointer<T>& r)
{
    return !(l == r);
}

}

#endif // SHAREDPOINTER_H

main.cpp測試

#include <iostream>
#include "SharedPointer.h"

using namespace std;
using namespace StLib;

class Test : public Object
{
public:
    int value;

    Test() : value(0)
    {
        cout << "Test()" << endl;
    }

    ~Test()
    {
        cout << "~Test()" << endl;
    }
};

int main()
{
    SharedPointer<Test> sp0 = new Test();
    SharedPointer<Test> sp1 = sp0;
    SharedPointer<Test> sp2 = NULL;

    sp2 = sp1;

    sp2->value = 100;

    cout << sp0->value << endl;
    cout << sp1->value << endl;
    cout << sp2->value << endl;

    cout << (sp0 == sp2) << endl;
    sp2.clear();
    cout << (sp0 == sp2) << endl;

    return 0;
}

執行結果為:

Test()
100
100
100
1
0
~Test()

智慧指標的使用軍規:

  • 只能用來指向堆空間中的單個變數( 物件 )
  • 不同型別的智慧指標物件不能混合使用
  • 不要使用 delete 釋放智慧指標指向的堆空間

3.小結

  • SharedPointer 最大程度的模擬了原生指標的行為
  • 計數機制確保多個智慧指標合法的指向同一片堆空間
  • 智慧指標只能用於指向堆空間中的記憶體
  • 不同型別的智慧指標不要混合使用
  • 堆物件的生命週期由智慧指標進行管理