智能指针(auto_ptr)vc版

auto_ptr包含于头文件 #include<memory> 其中<vector><string>这些库中也存有。auto_ptr 能够方便的管理单个堆内存对象,在你不用的时候自动帮你释放内存。

auto_ptr的设计目的:

        局部对象获取的资源(内存),当函数退出时,它们的析构函数被调用,从而自动释放这些资源,但是,如果以显式手法获得的资源(称为动态分配内存空间如:new、malloc等)没有绑定在任何对象身上,必须以显式手法释放。(如:delete,free等)。
         因此,这会出现一些麻烦,如我们忘掉delete,或者return语句在delete之前,例如:
 1 #include<iostream>
 2 using namespace std;
 3 int main()
 4 {
 5     int *p=new int(10);
 6     if(*p>2)
 7         return 0;
 8     delete p;
 9     p=NULL;
10 }
在没有delete之前函数已经返回。同时,如果此函数有异常出现时,函数将立刻退离,根本不会调用函数尾端的delete语句,这就会使内存遗失。当然我们也可以防止这种情况发生那就是在函数中用try。。catch语句,但是这回显的程序很复杂和累赘。
        如果使用智能指针,无论在任何情况下,只要自身摧毁就一定会释放资源。因为智能指针原理就是将指针转换为类对象,由于对象被销毁会自动调用类中的析构函数,释放对象所指向的内存空间从而达到自动释放资源的目的。
注意:auto_ptr它是“它所指向的对象”的拥有者。所以。当身为对象拥有者的auto_ptr被摧毁,auto_ptr要求一个对象只有一个拥有者,严禁一物二主(之后的拥有权转移也会提到)
一个版本的auto_ptr是Linux和VS中使用的,另一个是VC版本的,下面是VC版本的auto_ptr的源代码剖析:
c中的auto_ptr:
        源码:
vc:

template<class _Ty>
    class auto_ptr {
public:
    typedef _Ty element_type;
    explicit auto_ptr(_Ty *_P = 0) _THROW0()
        : _Owns(_P != 0), _Ptr(_P) {}
    auto_ptr(const auto_ptr<_Ty>& _Y) _THROW0()
        : _Owns(_Y._Owns), _Ptr(_Y.release()) {}
    auto_ptr<_Ty>& operator=(const auto_ptr<_Ty>& _Y) _THROW0()
        {if (this != &_Y)
            {if (_Ptr != _Y.get())
                {if (_Owns)
                    delete _Ptr;
                _Owns = _Y._Owns; }
            else if (_Y._Owns)
                _Owns = true;
            _Ptr = _Y.release(); }
        return (*this); }
    ~auto_ptr()
        {if (_Owns)
            delete _Ptr; }
    _Ty& operator*() const _THROW0()
        {return (*get()); }
    _Ty *operator->() const _THROW0()
        {return (get()); }
    _Ty *get() const _THROW0()
        {return (_Ptr); }
    _Ty *release() const _THROW0()
        {((auto_ptr<_Ty> *)this)->_Owns = false;
        return (_Ptr); }
private:
    bool _Owns;
    _Ty *_Ptr;
    };

 解析代码:

1.
#include <iostream>
#include <vld.h>
int main()
{
    int *p=new int(10)//初始化指针
        return 0;
}

运行结果:

 

 由于没有用delete释放内存空间,所以造成内存空间浪费了四个字节。

2.

#include<iostream>
using namespace std;

class Test
{
public:
    void fun()
    {
        cout << "Test::fun()" << endl;
    }
};
template<class _Ty>
class auto_ptr
{
public:
    explicit auto_ptr(_Ty *_P = 0) :_Owns(_P != 0), _Ptr(_P)
    {}
    auto_ptr(const auto_ptr<_Ty>&_Y):_Owns(_Y._Owns),_Ptr(_Y.release()){}
    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();  //修改_Y的拥有权,并将_Y的_Ptr赋值给该成员_Ptr从而使该对象具有_Y._Ptr指向空间的拥有权
        }
        return (*this);
    }
    _Ty& operator*()
    {
        return *_Ptr;
    }
    _Ty* operator->()
    {
        return _Ptr;
    }
    _Ty*release()const
    {
        ((auto_ptr<_Ty>*)this)->_Owns = false;
        return (_Ptr);
    }
    ~auto_ptr()
    {
        if (_Owns)
            delete _Ptr;
    }
private:
    bool _Owns;//拥有权
    _Ty *_Ptr;

};

int main()
{
    int *p = new int(10);
    auto_ptr<int> pl(p);
    cout << *pl << endl;
    Test *pc = new Test;
    auto_ptr<Test> temp(pc);
    temp->fun();
    auto_ptr<int>pal = pl;
    cout << *pal << endl;
    auto_ptr<int>pt;
    pt = pal;
    cout << *pal << endl;
    cout << *pt << endl;
    
    return 0;
}
   auto_ptr(const auto_ptr<_Ty>&_Y):_Owns(_Y._Owns),_Ptr(_Y.release()){}//此处的const并非意味你不能更改auto_ptr所拥有的对象,而是意味你不能更改auto_ptr的拥有权。(通俗讲就是如果使用const auto_ptr作为参数,对新对象的任何赋值操作都将导致编译期错误。就常数特性而言,const auto_ptr比较类似常数指针(T*const p),而非指向常数的指针(const  T*p)——尽管其语法看上去比较像后者。所以_Y.release()改变了_Y.Owns的值不影响函数运行。
1 _Ty*release()const
2  {
3   ((auto_ptr<_Ty>*)this)->_Owns = false;
4   return (_Ptr);
5  }

         同时这里因为函数是const修饰的常函数所以不能对其进行修改,但是((auto_ptr<_Ty>*)this)其意义是将const (auto_ptr<_Ty>*)类型强制转换为(atuo_ptr<_Ty*>类型,这样就可以对_Owns进行修改,但是这只能在强制之时进行修改,一旦执行完强转其类型依然变为原来的const (auto_ptr<_Ty>*)类型,使其它方法无法修改其中数据。

运行结果  :
no memory leaks 无内存泄漏
     这里有一些问题,为什么*pal的拥有权已经转移却还能输出呢?因为vc版的auot_ptr就是将拥有权转移后,除了不能够对其多次析构外,还可以对其进行操作,这就不好了,你都已经分手了,还不放手。在VS版本上对拥有权有更好的管理。

 

posted @ 2019-02-22 21:30  Shallow_tipsy  阅读(173)  评论(0编辑  收藏  举报