模拟实现智能指针

众所周知,智能指针是用来管理指针的,为了避免开辟了空间而忘记释放的情况。
下面我们分别来模拟实现以下boost库中三种智能指针的实现,他们分别是auto ptr,scoped ptr,shared ptr。

一.auto ptr

  1. 旧版本的实现:
template <typename T>
class Auto_ptr
{
public:
    Auto_ptr(T*ptr = NULL) :_ptr(ptr), state(true)
    {}
    ~Auto_ptr()
    {
        if (state&&NULL != _ptr)
        {
            delete _ptr;
        }
    }
    Auto_ptr(const Auto_ptr<T>&sp)
    {
        _ptr = sp._ptr;
        sp.state = false;//赋值以后将状态置为false;
    }
    Auto_ptr<T>&operator=(const Auto_ptr<T>&sp)
    {
        if (this != &sp)
        {
            if (_ptr)
            {
                delete _ptr;
                _ptr = NULL;
            }
            _ptr = sp._ptr;
            sp.state = false;//赋值以后将状态置为false;
        }
        return *this;
    }
private:
    T*_ptr;
    bool state;
};

2.新版本的实现:
赋值以后将原指针置为空,而不是改变状态

3.总结
auto ptr只适用于单个的指针的情况,当进行对象之间的赋值的时候会使所有权转移。所以建议在任何情况下都不使用auto ptr。

二.scoped ptr

scoped ptr是对auto ptr的改进,将拷贝构造以及赋值操作符的重载设为私有。适用于开辟一个类型空间的指针以及多个类型空间的指针。

三.shared ptr

template<typename T>
class Shared_ptr
{
public:
    Shared_ptr(T*ptr = NULL) :_ptr(ptr), pcount(NULL)
    {
        if (NULL != _ptr)
        {
            pcount = new int(1);
        }
    }
    ~Shared_ptr()
    {
        if (_ptr&&--(*pcount) == 0)
        {
            delete _ptr;
            delete pcount;
        }
    }
    Shared_ptr(const Shared_ptr<T>&sp)
    {
        _ptr = sp._ptr;
        pcount = sp.pcount;
        ++(*pcount);
    }
    Shared_ptr<T>&operator=(const Shared_ptr<T>&sp)
    {
        if (this != &sp)
        {
            if (_ptr&&--(*pcount)==0)
            {
                delete pcount;
                delete _ptr;
            }
            pcount = sp.pcount;
            _ptr = sp._ptr;
            ++(*pcount);
        }
        return *this;
    }
    int use_count()
    {
        return *pcount;
    }
private:
    T*_ptr;
    int*pcount;
};

使用引用计数进行实现,适用于开辟多个空间的指针和一个空间的指针。可以进行指针间的赋值。但是它同时也带来了一些问题。
1. 引用计数更新存在着线程安全(这里暂且不提)
2. 循环引用
3. 定置删除器

这里重点讲一下循环引用的问题:

struct ListNode
{
    shared_ptr<ListNode> _prev;
    shared_ptr<ListNode> _next;
    /*weak_ptr<ListNode > _prev;
    weak_ptr<ListNode > _next;*/
    ~ListNode()
    {
        cout << "~ListNode()" << endl;
    }
};
void Test()
{
    // 循环引用问题
    shared_ptr <ListNode > p1(new ListNode());
    shared_ptr <ListNode > p2(new ListNode());
    cout << "p1->Count:" << p1.use_count() << endl;//1
    cout << "p2->Count:" << p2.use_count() << endl;//1
    // p1节点的_next指向 p2节点
    p1->_next = p2;
    // p2节点的_prev指向 p1节点
    p2->_prev = p1;
    cout << "p1->Count:" << p1.use_count() << endl;//2
    cout << "p2->Count:" << p2.use_count() << endl;//2
}

由代码可知p1本就维护一块空间,现将p1赋值给p2的_next也就两个指针在维护一块空间,p1的引用计数为2,p2的引用计数也为2。
(1)当p2出了作用域,引用计数变为1,不为0,所以没有释放空间。
(2)当p1出了作用域,引用计数变为1,不为0,所以没有释放空间。
画个图来解释一下(1)(2):
这里写图片描述
p2出作用域,它本身要调用析构函数,所以引用计数减1,但此时p1的_next的值是p2,也就是说p2同时被p1管理着,p1的空间没有释放,所以p2的引用计数不会变为0。
同理,因为p2没有释放,p1也无法释放。

解决:将ListNode中_prev和_next的类型设为weak ptr类型。
原因:weak ptr和shared ptr都是引用计数基类的派生类并且weak ptr维护的引用计数和shared ptr的不一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值