C++11智能指針shared_ptr的實現思路(內附實現和測試代碼)

由於面試的時候被問到過幾次智能指針,所以閒下來打算從頭理一遍智能指針的實現思路,自己實現一個shared_ptr,也能夠更好地理解智能指針。

智能指針說白了就是用類把指針封裝起來,這樣就不必擔心內存泄漏的問題了,因爲類的對象在出作用域的時候會自動調用析構函數。

因此智能指針要具備指針的基本功能:

  1. 首先要有一個T類型的指針,用於封裝實際的指針(初始化);
  2. 其次一定要有一個int型指針,用於引用計數,同步更新指向同一內存空間的智能指針有多少個;
  3. 要自己寫構造函數、拷貝構造函數、拷貝賦值函數及析構函數;
  4. 重載 解引用運算符 * 和 指向運算符 -> ;
  5. 最後useCount函數用於獲取該對象所封裝指針的引用計數。

另外還編寫了幾個測試樣例,用於驗證是否實現了shared_ptr的基本功能,具體代碼如下:

#include <iostream>
using namespace std;

template<typename T>
class SharedPtr {
  private:
    T* m_ele;
    int* m_num;

  public:
    SharedPtr(): m_ele(nullptr){
        cout << "Hello Constructor 1 !" << endl;
        m_num = new int(0);
    }

    SharedPtr(T* x): m_ele(x){
        cout << "Hello Constructor 2 !" << endl;
        m_num = new int(1);
    }

    SharedPtr(const SharedPtr& x){
        cout << "Hello Copy Constructor !" << endl;
        m_ele = x.m_ele;
        m_num = x.m_num;
        (*m_num)++;
    }

    /*
    關於拷貝賦值函數,這裏返回值加引用和不加引用區別很大:

    如果返回值是引用對象的話,拷貝賦值時只會調用該賦值函數;

    如果返回值是值對象,除了要調用該賦值函數,還要在該賦值函數結束時調用copy構造函數
    創建一個臨時對象作爲返回值,返回後賦給等號左邊的對象,
    這個臨時對象完成其使命後,在該賦值語句結束時,會調用析構函數,釋放該臨時對象

    因此不加引用會比加引用多調用一次拷貝賦值和析構函數,這點一定要明確!
    */
    SharedPtr& operator=(const SharedPtr& x){
        cout << "Copy Assignment !" << endl;
        (*m_num)--;
        if((*m_num) == 0){
            delete m_ele;
            delete m_num;
        }
        m_ele = x.m_ele;
        m_num = x.m_num;
        (*m_num)++;
        return *this;  //不是構造函數,要有返回值!
    }

    T&  operator*(){
        return *(this->m_ele);
    }

    T* operator->(){
        return this->m_ele;
    }

    ~SharedPtr(){
        cout << "Hello Destructor ! I'm " << *m_ele << endl;
        //調用析構函數,則其引用計數減1,若引用計數減爲0,則將其封裝的指針和計數指針都釋放掉
        (*m_num)--;
        if((*m_num) == 0){
            delete m_ele;
            delete m_num;
        }
    }

    int useCount(){
        return *(this->m_num);
    }
};



int main() {
    int* x=new int(520);
    SharedPtr<int> test(x);
    cout << "test引用計數: " << test.useCount() << "    指向內存的值:" << *test << endl;

    int* y=new int(250);
    SharedPtr<int> test2(y);
    cout << "test2引用計數: " << test2.useCount() << "    指向內存的值:" << *test2 << endl;

    SharedPtr<int> test3(test2);
    cout << "test2引用計數: " << test2.useCount() << "    指向內存的值:" << *test2 << endl;
    cout << "test3引用計數: " << test3.useCount() << "    指向內存的值:" << *test3 << endl;

    test3 = test;
    cout << "test引用計數: " << test.useCount() << "    指向內存的值:" << *test << endl;
    cout << "test2引用計數: " << test2.useCount() << "    指向內存的值:" << *test2 << endl;
    cout << "test3引用計數: " << test3.useCount() << "    指向內存的值:" << *test3 << endl;
    return 0;
}

最終的輸出結果表明該實現是準確的,結果如下:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章