C++智能指针(二):模拟实现三种智能指针

上一篇博客我们简单介绍了智能指针:简单介绍智能指针

有关shared_ptr的循环引用问题可以参考博客:weak_ptr–解决shared_ptr循环引用问题

auto_ptr

模拟实现

template<class T>
class Autoptr
{
public:
    Autoptr(T* ptr = NULL)
        :_ptr(ptr)
    {}

    Autoptr(Autoptr<T>& ap)
    {
        _ptr = ap._ptr;
        ap._ptr = NULL;
    }

    Autoptr<T>& operator=(Autoptr<T>& ap)
    {
        if (this != &ap)
        {
            delete _ptr;
            _ptr = ap._ptr;
            ap._ptr = NULL;
        }

        return *this;
    }

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

    T operator*()
    {
        return *_ptr;
    }

    ~Autoptr()
    {
        delete _ptr;
        _ptr = NULL;
    }

    void Reset(T* ptr = 0)
    {
        if (_ptr != ptr)
        {
            delete _ptr;
        }
        _ptr = ptr;
    }
protected:
    T* _ptr;
};

void APTest()
{
    Autoptr<int> ap1(new int(10));
    cout <<"*ap1 = "<< *ap1 << endl;

    Autoptr<int> ap2(ap1);
    cout <<"*ap2 = "<< *ap2 << endl;

    Autoptr<int> ap3(new int(20));
    ap3 = ap2;
    cout <<"*ap3 = "<< *ap3 << endl;

    //cout << *ap1 << endl;//报错
}

测试结果:
这里写图片描述

代码分析

代码中的Reset()函数是干嘛的?

void Reset(T* ptr = 0)
    {
        if (_ptr != ptr)
        {
            delete _ptr;
        }
        _ptr = ptr;
    }

答:为了重置一个auto_ptr对象,必须使用reset()函数。可以向reset()传递一个指针,如果不希望设置该auto_ptr对象的话,可以传递一个0值。如果auto_ptr当前指向一个对象并且该auto_ptr对象拥有该对象的所有权,则该对象再底层指针重置之前,首先被删除。例如:

void APTest()
{
    int *pi = new int(20);
    auto_ptr<int>_auto_ptr(pi);
    cout << "_auto_ptr = " << *pi << endl;

    int *pi2 = new int(30);
    _auto_ptr.reset(pi2);
    cout << "pi->" << *pi << endl;
    cout << "pi2->" << *pi2 << endl;
}

输出结果:
这里写图片描述

我们可以在输出结果的第二行看到,pi已经变成了随机值。reset()函数将auto_ptr对象原来指向的那块动态分配的空间释放了。

上面的代码还有一句:

//cout << *ap1 << endl;//报错

为什么报错??
这是因为ap1已经把它指向的空间交给了ap2去管理,所以ap1已经不具备访问原来自己所指向的空间的权限。所以对它进行解引用是非法的。
所以可以看清auto_ptr的本质是管理权的转移,即ap1将自己所指向的空间交给ap2来管理,析构也是由ap2来完成。

scoped_ptr

由于auto_ptr的严重缺陷,所以后来引入了scoped_ptr。防拷贝,意思就是不能进行拷贝,简单地说是一种简单粗暴的方式。

模拟实现

template<class T>
class  Scopedptr
{
public:
    Scopedptr(T* ptr = NULL)
        :_ptr(ptr)
    {}

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

    T operator*()
    {
        return *_ptr;
    }

    ~Scopedptr()
    {
        delete _ptr;
        _ptr = NULL;
    }

protected:
    Scopedptr(Scopedptr<T>& sp);
    Scopedptr<T>& operator=(const Scopedptr<T>& p);
private:
    T* _ptr;
};

void SPTest()
{
    Scopedptr<int> sp(new int(10));
    cout << "sp = " << *sp << endl;
}

scoped_ptr中对拷贝构造函数和赋值运算符的重载函数只是进行了声明,并没有去定义这两个函数,而且声明为protected或者是private,这是防止别人在类外对这两个函数进行定义。防止拷贝,所以说scope_dptr是一种简单粗暴的方式。

shared_ptr

编写程序往往要用到拷贝,这样scopedptr就不能起到相应的作用,所以便有了shared_ptr。
shared_ptr->采用了引用计数,优点是功能强大,但是也有缺点,缺点是过于复杂,而且会引起循环引用。

template<class T>
class Sharedptr
{
public:
    Sharedptr(T* ptr = NULL)
        :_ptr(ptr)
        , pcount(0)
    {
        if (_ptr != NULL)
            pcount = new int(1);
    }

    Sharedptr(const Sharedptr<T>& sp)
    {
        _ptr = sp._ptr;
        pcount = sp.pcount;
        ++(*pcount);
    }

    Sharedptr<T>& operator=(const Sharedptr<T>& sp)
    {
        if (this != &sp)
        {
            if (_ptr && --(*pcount) == 0)
            {
                delete pcount;
                delete _ptr;
            }
            pcount = sp.pcount;
            _ptr = sp._ptr;
            ++(*pcount);
        }

        return *this;
    }

    ~Sharedptr()
    {
        if (_ptr && --(*pcount) == 0)
        {
            delete _ptr;
            delete pcount;
        }
    }

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

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

    T Getpcount()
    {
        return *(pcount);
    }

    void Realease()
    {
        if (--(*pcount) == 0)
        {
            delete _pcount;
            delete _ptr;
        }
    }

    void Reset(T* ptr, int* pcount)
    {
        if (_ptr != ptr)
        {
            delete _ptr;
            delete _pcount;
        }

        _ptr = ptr;
        _pcount = pcount;
    }
private:
    T* _ptr;
    T* pcount;
};

void Test()
{
    Sharedptr<int> s1(new int(10));
    cout << "s1 = " << *s1 << endl;
    cout << "pcount = " << s1.Getpcount() << endl;

    Sharedptr<int> s2(s1);
    cout << "s2 = " << *s2 << endl;
    cout << "pcount = " << s2.Getpcount() << endl;

    Sharedptr<int> s3;
    s3 = s1;
    cout << "s3 = " << *s3 << endl;
    cout << "pcount = " << s3.Getpcount() << endl;
}

测试结果:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值