auto_ptr剖析

虽然auto_ptr已经被C++11弃用了,但是通过分析它的代码仍然能够学习到一些知识。
auto_ptr的动机:动态开辟内存的时候,new完之后必须delete,否则会产生内存泄漏。但是如果程序在delete之前发生异常,那么delete语句就不能执行,就会产生内存泄漏。auto_ptr技术正是为了解决这一问题而存在的。首先需要引入包含其的头文件#include< memory >。智能指针本质上实际是一个对象,但它重载了"*“和”->"运算符。对象在销毁的时候,会自动调用析构函数。所以智能指针能实现的关键在此。
下面简单演示一下auto_ptr的用法:

#include <iostream>
#include <string>
#include <memory>
using namespace std;
int main(){
    int *p = new int(10);
    auto_ptr<int>pa(p);
    cout<<*pa<<endl;//10
    *pa = 100;
    cout<<*pa<<endl;//100
    
    auto_ptr<string>ps(new string("hello world"));
    cout<<ps->size()<<endl;//11
}

智能指针的关键在于拥有权的转移
拷贝构造和赋值的时候,要进行拥有权转移,保证一个空间只由一个对象拥有。
下面是VC++6.0中auto_ptr的实现:

#include <iostream>
#include <string>
#include <memory>
//using namespace std;
//智能指针  //自动调用  业务理解
//拥有权的转移
template<class _Ty>
class auto_ptr
{
public:
    explicit auto_ptr(_Ty *_P = 0)
        : _Owns(_P != 0), _Ptr(_P)
    {}
    //auto_ptr<int> pa1 = pa;
    //const auto_ptr<_Ty> * _Y
    auto_ptr(const auto_ptr<_Ty> &_Y)
        : _Owns(_Y._Owns), _Ptr(_Y.release())
    {}
    //auto_ptr<int> pa1;
    //pa1 = pa;
    auto_ptr<_Ty> &operator=(const auto_ptr<_Ty> &_Y)
    {
        if (this != &_Y) {
            if (_Ptr != _Y._Ptr) {
                if (_Owns)
                    delete _Ptr;
                _Owns = _Y._Owns;
            }
            else if (_Y._Owns)
                _Owns = true;

            _Ptr = _Y.release();
        }
        return (*this);
    }

    ~auto_ptr()
    {
        if (_Owns)
            delete _Ptr;
    }
public:
    _Ty &operator*() const
    {
        return *_Ptr;
    }
    _Ty *operator->() const
    {
        return _Ptr;
    }
    _Ty *release() const
    {
        ((auto_ptr<_Ty> *) this)->_Owns = false;
        return _Ptr;
    }
private:
    bool _Owns;
    _Ty *_Ptr;
};

int main()
{
    int *p = new int(10);
    int *p1 = new int(20);

    auto_ptr<int> pa(p);
    //........
    pa.release();

    auto_ptr<int> pa1(p);
    pa1 = pa;
}

当pa2 = pa1时 :

1.pa2 无指向 : 将pa1的指针给pa2赋值,再将pa1将拥有权进行转移;
2.pa2 有指向不同于pa1的对象 : 将pa2的指向进行析构,再将pa1的指针给pa2赋值,将pa1的拥有权转移;
3.pa2 有指向和pa1相同的对象 : 判断pa1是否有拥有权,有则将pa1的拥有权转移给pa2。

但vc版的auot_ptr也有一些问题,就是将拥有权转移后,除了不能够对其多次析构外,还可以对其进行操作,这就不好了,你都已经分手了,还不放手。在VS版本上对拥有权有更好的管理。如果两个指针指向一个空间但是都没有拥有权,最后需要用delete释放。
下面是VS中的auto_ptr的实现:

//假设全局pa2都是用pa1来构造
//如:pa2(pa1)、pa2=pa1

template<class _Ty>    //auto_ptr类声明
class auto_ptr;

template<class _Ty>
struct auto_ptr_ref    //auto_ptr的辅助类
{
    explicit auto_ptr_ref(_Ty *_Right): _Ref(_Right)
    {}
    _Ty *_Ref;
};

template<class _Ty>    
class auto_ptr//auto_ptr类
{
public:
    typedef auto_ptr<_Ty> _Myt;    //管理类的类型
    typedef _Ty element_type;    //被管理元素的类型

    explicit auto_ptr(_Ty *_Ptr = 0) : _Myptr(_Ptr)    //构造
    {}    //从原始指针中获取控制权

    //若pa2(pa1);
    auto_ptr(_Myt& _Right) : _Myptr(_Right.release())    //拷贝构造
    {}

    //若:pa2(pa1)
    auto_ptr(auto_ptr_ref<_Ty> _Right)
    {
        // 用右值来构造
        _Ty *_Ptr = _Right._Ref;    //将pa1的指针保存在Ptr中
        _Right._Ref = 0;    // 将pa1的指针指向空
        _Myptr = _Ptr;    // 将pa2的地址指向pa1的地址
    }

    template<class _Other>
    operator auto_ptr<_Other>()        //转换为可转换的类型
    {
        return (auto_ptr<_Other>(*this));
    }

    template<class _Other>
    operator auto_ptr_ref<_Other>()        //隐式类型转换,将auto_ptr类型指针转换为auto_ptr_ref类型
    {
        _Other *_Cvtptr = _Myptr;
        auto_ptr_ref<_Other> _Ans(_Cvtptr);
        _Myptr = 0;
        return (_Ans);
    }

    template<class _Other>
    _Myt& operator=(auto_ptr<_Other>& _Right)    //针对可转换为 _Ty* 类型的 _Other* 类型的拷贝函数
    {
        reset(_Right.release());
        return (*this);
    }

    template<class _Other>    //特定类型构造函数
    auto_ptr(auto_ptr<_Other>& _Right) : _Myptr(_Right.release())
    {}    //针对可转换为 _Ty* 类型的 _Other* 类型的构造函数

    //若:pa2=pa1
    _Myt& operator=(_Myt& _Right)    //拷贝赋值函数
    {
        reset(_Right.release());
        return (*this);
    }

    //若:pa2=pa1
    _Myt& operator=(auto_ptr_ref<_Ty> _Right)    //将一个 auto_ptr_ref 类型的变量赋值给 *this
    {
        _Ty *_Ptr = _Right._Ref;    //将pa1的Ref指针赋值给pa2的_Ptr指针
        _Right._Ref = 0;    // 将pa1的Ref指针指向空
        reset(_Ptr);    // 将pa2的_Myptr指向pa1
        return (*this);
    }

    ~auto_ptr()     //析构
    {
        delete _Myptr;    //析构指针所指向的内容
    }

    _Ty& operator*() const    //重载*
    {
        if (_Myptr == 0)
        {
            _DEBUG_ERROR("auto_ptr not dereferencable");
        }
        return (*get());
    }

    _Ty *operator->() const        //重载->
    {
        return (get());
    }

    _Ty *get() const    //用来返回_Myptr的地址
    {
        return (_Myptr);
    }

    _Ty *release()    //将一个对象的_Myptr记住,再指向空,然后再把其记住的地址返回
    {
        _Ty *_Tmp = _Myptr;    //先将pa1的指针用Tmp保存,
        _Myptr = 0;        //再讲pa1的指针指向空
        return (_Tmp);    //    返回Tmp即原来pa1指向的地址
    }

    void reset(_Ty *_Ptr = 0)    //将this的_Myptr指向传进来的指针的地址
    {
        if (_Ptr != _Myptr)    //如果pa1“以前的”(pa1在release()中被指向空,就是返回的那个Tmp用来记住pa1以前的那个地址)那个地址所指向的地址不等于pa2的地址
            delete _Myptr;    //先析构pa2所指向的地址

        _Myptr = _Ptr;        //再将pa2地址指向返回来的pa1的老地址
    }

private:
    _Ty *_Myptr;
};

PS:这篇博文讲的特别好auto_ptr源码剖析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值