手动编写智能指针

103 阅读1分钟

为什么需要智能指针

普通指针在资源访问中导致的指针悬空问题

指针悬空问题

#include<iostream>
#include<string>

using namespace std;

class Data {
public:
    Data(string str) : _str(str) {
        cout << "Constructor" << endl;
    }

    ~Data() {
        cout << "Destructor" << endl;
    }

    void dis() {
        cout << _str << endl;
    }

private:
    string _str;
};

int main() {
    Data *pstr1 = new Data("I Love China");
    Data *pstr2 = pstr1;
    Data *pstr3 = pstr1;
    pstr1->dis();
    delete pstr1;
    pstr2->dis();
    return 0;
}

以上程序编译会正常通过,但是因为指针指向的原来的对象已经被释放,所以程序运行时会打印乱码。

指针悬空问题的解决方法

为了解决这个问题,C++中引入了引用计数的概念,引用计数的思想是:每一个对象都有一个引用计数,当有一个指针指向该对象时,该对象的引用计数加1,当指针不再指向该对象时,该对象的引用计数减1,当该对象的引用计数为0时,该对象被释放。

#include<iostream>
#include<string>

using namespace std;

class Data {
public:
    Data(string str) : _str(str) {
        cout << "Constructor" << endl;
    }

    ~Data() {
        cout << "Destructor" << endl;
    }

    void dis() {
        cout << _str << endl;
    }

private:
    string _str;
};

class Count    //Count类用于存储指向同一资源的指针数量
{
public:
    friend class SmartPtr;

    Count(Data *pdata) : _pdata(pdata), _count(1) {
        cout << "Count类构造函数" << endl;
    }

    ~Count() {
        cout << "Count类析构函数" << endl;
        delete _pdata;
    }

private:
    Data *_pdata;
    int _count;
};

//使用指针实现智能指针
class SmartPtr   //SmartPtr类用于对指向Data类对象的指针实现智能管理
{
public:
    SmartPtr(Data *pdata) : _reNum(new Count(pdata)) {
        cout << "创建基类对象" << endl;
    }

    SmartPtr(const SmartPtr &another) : _reNum(another._reNum) {
        ++_reNum->_count;
        cout << "Smartptr类复制构造函数" << endl;
    }

    ~SmartPtr() {
        if (--_reNum->_count == 0) {
            delete _reNum;
            cout << "Smartptr类析构函数" << endl;
        }
    }

    Data *operator->() {
        return _reNum->_pdata;
    }

    Data &operator*() {
        return *_reNum->_pdata;
    }

    int disCount() {
        return _reNum->_count;
    }

private:
    Count *_reNum;
};

int main() {
    Data *pstr1 = new Data("I Love China!");
    SmartPtr pstr2 = pstr1;
    (*pstr1).dis();
    SmartPtr pstr3 = pstr2;
    pstr2->dis();
    cout << "使用基类对象的指针数量:" << pstr2.disCount() << endl;
    return 0;
}

以上代码实现了一件事,就是在所有包含原始对象Data的包装对象都被析构之后再释放原始的Data对象,类似于默认拷贝构造函数中的浅拷贝。

这就是智能指针的核心原理。