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;
}

最终的输出结果表明该实现是准确的,结果如下:
在这里插入图片描述

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