当前位置: 首页>编程语言>正文

C++技能点之智能指针(二)

C++技能点之智能指针(二),第1张
智能指针思维导图

上一篇:C++技能点之智能指针(一)

五、如何实现一套简单的智能指针

  • 先来看一段代码,来自C++ 智能指针:原理与实现[1]
// SmartPointer.h
#include <iostream>
using namespace std;

template<class T>
class SmartPointer
{
public:
    SmartPointer();
    SmartPointer(T* target);
    SmartPointer(const SmartPointer<T>& from);
    ~SmartPointer();

    static T* New();

    bool operator == (const SmartPointer<T>& other) const;
    bool operator != (const SmartPointer<T>& other) const;
    SmartPointer<T>& operator = (const SmartPointer<T>& that);
    T& operator*() const;
    T* operator->() const;

    int getRefCount();
protected:
    void addReference();
    void removeReference();

private:
    T* m_Pointer; // 指向资源的指针
    int* m_RefPointer;  // 指向引用计数的指针
};

template<typename T>
SmartPointer<T>::SmartPointer()
    : m_Pointer(nullptr), m_RefPointer(nullptr){}

template<typename T>
SmartPointer<T>::SmartPointer(T* target)
    : m_RefPointer(nullptr), m_Pointer(target) 
{
    addReference();
}

template<typename T>
SmartPointer<T>::SmartPointer(const SmartPointer<T>& from)
    : m_RefPointer(from.m_RefPointer), m_Pointer(from.m_Pointer)
{
    addReference();
}

template<typename T>
T* SmartPointer<T>::New()
{
    return new T();
}

template<typename T>
SmartPointer<T>::~SmartPointer()
{
    removeReference();
}

template<typename T>
void SmartPointer<T>::addReference()
{
    if(m_RefPointer)
        (*m_RefPointer)++;
    else
        m_RefPointer = new int(1);
}

template<typename T>
void SmartPointer<T>::removeReference()
{
    if(m_RefPointer){
        (*m_RefPointer)--;
        if(*m_RefPointer == 0)
        {
            delete m_RefPointer;
            delete m_Pointer;
            m_RefPointer = nullptr;
            m_Pointer = nullptr;
        }
    }
}

template<typename T>
bool SmartPointer<T>::operator == (const SmartPointer<T>& other) const
{
    return m_Pointer == other.m_Pointer;
}

template<typename T>
bool SmartPointer<T>::operator != (const SmartPointer<T>& other) const
{
    return !operator==(other);
}

template<typename T>
SmartPointer<T>& SmartPointer<T>::operator = (const SmartPointer<T>& that)
{
    if(this != &that)
    {
        removeReference();
        this->m_Pointer = that.m_Pointer;
        this->m_RefPointer = that.m_RefPointer;
        addReference();
    }
    return *this;
}

template<typename T>
T& SmartPointer<T>::operator*() const
{
    return *m_Pointer;
}

template<typename T>
T* SmartPointer<T>::operator->() const
{
    return m_Pointer;
}

template<typename T>
int SmartPointer<T>::getRefCount()
{
    if(m_RefPointer)
        return *m_RefPointer;
    return -1;
}
  • 先来分析一下这段代码,这一段实现了智能指针的基本功能。包含了默认的构造函数,裸指针构造,拷贝构造,析构函数;添加了静态New()方法,重载了几种常见的运算符(判断是否相等和不相等,赋值,解引用和访问成员函数运算符),当然还有引用计数的部分(增加,减少,取值)。由于智能指针需要对所有数据类型适用,最好的实现方式就是采用模板类的方式。
  • 首先由于每块资源都要有一个引用计数,所以要有一个指向引用计数的指针,用来管理指向这块资源的指针数。
  • 对于引用计数,addReference()即增加引用计数,如果引用计数的指针为空就new一个新的,如果不为空就加1。removeReference()同理,如果引用计数指针不为空就减1,如果减到0就delete掉指向资源的指针及引用计数的指针。
  • 对于构造函数,默认构造函数不指向资源,所以指针均为空;裸指针构造,有指向资源的指针,但引用计数并不记录所有指针的个数,而是只记录智能指针的个数,所以引用计数指针为空并初始化引用计数;拷贝构造就将另一个智能指针的指向和引用计数均记录下来;而静态的New()方法是为了统一用法封装了一层。
  • 接下来用一段代码测试一下,来自C++ 智能指针:原理与实现 [1]
#include <iostream>
#include "SmartPointer.h"
using namespace std;

class A
{
public:
    A() { cout << "constuct = " << this << endl; };
    ~A() { cout << "destruct = " << this << endl; };

    void Print()
    {
        cout << "print() = " << this << endl;
    }
};

int main()
{
    SmartPointer<A> sp_outer;
    {
        cout << "start " << endl;
        SmartPointer<A> sp_1 = SmartPointer<A>::New();
        cout << "create smart pointer, refCount = " << sp_1.getRefCount() << endl;

        SmartPointer<A> sp_2 = sp_1;
        cout << "object construct, refCount = " << sp_2.getRefCount() << endl;

        sp_1 = SmartPointer<A>::New();
        cout << "origin refCount = " << sp_2.getRefCount()
            << ", current refCount = " << sp_1.getRefCount() << endl;

        sp_1->Print();

        sp_outer = sp_1;

        cout << "end" << endl;
    }
    cout << "finish" << endl;
}
  • 这段代码很简单,就是为了测试一下我们的智能指针是否能得到正确的结果。结果如下:
start
constuct = 0x100100360
create smart pointer, refCount = 1
object construct, refCount = 2
constuct = 0x100100630
origin refCount = 1, current refCount = 1
print() = 0x100100630
end
destruct = 0x100100360
finish
destruct = 0x100100630
  • 这段结果中唯一要解释一下的是当sp_1再次调用静态New()方法时,相当于重新构建智能指针,此时指向之前资源的引用计数会减1,所以导致origin refCount = 1。其余的输出结果符合预期,如有不懂的可以参照前篇 上一篇:C++技能点之智能指针(一)
  • 多说一点,其实这段代码中还可以继续完善,比如可以考虑把引用计数再进行封装,需要注意引用计数的原子性,感兴趣的朋友可以进一步更改参照std::shared_ptr

参考

[1] C++ 智能指针:原理与实现【这篇写的很好】


https://www.xamrdz.com/lan/5zd1848550.html

相关文章: