欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

智能指针——shared_ptr&weak_ptr

程序员文章站 2022-06-02 13:56:27
...

一个带有定制删除器的shared_ptr,因为有些指针比如说文件中指针,我们在释放文件指针的时候不能简单的使用free直接将文件指针释放掉,此时我们就应该传入一个仿函数,在我们传入文件指针的时候,调用这个仿函数来释放这个指针即可,不同的指针定制不同的释放函数这是我们的思想

template <class T>
struct Delete
{
    void operator()(T *_ptr)
    {
        if (_ptr)
        {
            delete _ptr;
        }
    }
};

//文件仿函数
struct Fclose
{
    void operator()(FILE *ptr)
    {
        fclose(ptr);
    }   
};
//定制一个删除的仿函数
template <class T,class D = Delete<T>>
class Shared_ptr
{
public:
    //没有定制删除器的Shared_ptr
    Shared_ptr(T *ptr)
        :_ptr(ptr),
        _pcount(new int(1))
    {}

    //有定制删除器的
    Shared_ptr(T *ptr, D d)
        :_ptr(ptr),
        _pcount(new int(1)),
        _d(d)
    {}

    //拷贝构造
    //不拷贝直接++
    Shared_ptr(const Shared_ptr<T, D>& ap)
        :_ptr(ap._ptr),
        _pcount(ap._pcount)
    {
        ++(*ap._pcount);
    }

    //赋值运算符的重载
    Shared_ptr<T, D>& operator=(Shared_ptr<T, D>& ap)
    {
        if (this != &ap)
        {
            //当引用计数为1的时候直接删除,然后赋值
            if (--(*_pcount) == 0)
            {
                delete _ptr;
                delete _pcount;
            }       
        }

        //当引用计数不为1的时候,直接赋值即可
        _ptr = ap._ptr;
        _pcount = ap._pcount;
        ++(*_pcount);
        return *this;
    }

    ~Shared_ptr()
    {
        if (--(*_pcount) == 0)
        {
            delete _pcount;
            if (_ptr)
            {
                _d(_ptr);
                printf("delete %p", _ptr);
            }
        }
    }

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

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

    operator void*()
    {
        return _ptr;
    }
public:
    T *_ptr;
    int *_pcount;
    D _d;//定制删除器
};

void test()
{
    Shared_ptr<string> sp(new (string));
    Shared_ptr<FILE, Fclose> sp3(fopen("test.txt", "w"), Fclose());
}

int main()
{
    test();
}

但是此时我们的shared_ptr还有一个循环引用的问题
栗子

struct ListNode
{
    Shared_ptr<ListNode> _prev;
    Shared_ptr<ListNode> _next;

    int _data;
    ListNode()
        :_prev(NULL),
        _next(NULL)
    {}
};

void ListTest()
{
    Shared_ptr<ListNode> node1 = new ListNode;
    Shared_ptr<ListNode> node2 = new ListNode;

    node1->_next = node2;
    node2->_prev = node1;
}

智能指针——shared_ptr&weak_ptr

解决方法:weak_ptr

template <class T>
class Weak_ptr
{
public:
    Weak_ptr(const Shared_ptr<T>& ap)
        :_ptr(ap._ptr)
    {}

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

    T& operator*()
    {
        return *_ptr;
    }
    T *_ptr;
};
struct ListNode
{
    //有循环引用的
    /*Shared_ptr<ListNode> _prev;
    Shared_ptr<ListNode> _next;*/

    //无循环引用
    Weak_ptr<ListNode> _prev;
    Weak_ptr<ListNode> _next;

    int _data;
    ListNode()
        :_prev(NULL),
        _next(NULL)
    {}
}; 

void ListTest()
{
    Shared_ptr<ListNode> node1 = new ListNode;
    Shared_ptr<ListNode> node2 = new ListNode;

    cout << *(node1._pcount) << endl;
    cout << *(node2._pcount) << endl;


    node1->_next = node2;
    node2->_prev = node1;

    cout << *(node1._pcount) << endl;
    cout << *(node2._pcount) << endl;
}

有循环引用的结果
智能指针——shared_ptr&weak_ptr

无循环引用的结果
智能指针——shared_ptr&weak_ptr

其实我们只是将两个节点之间的指针换成了weak_ptr,没有引用计数的指针,那此时就当然不会存在循环引用的问题了,想释放直接一下就可以释放,而将我们的node1和node2设为shared_ptr,这个有循环引用是没有问题的,不会发生循环引用