智能指针之auto_ptr和scoped_ptr

Posted wangshaowei

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了智能指针之auto_ptr和scoped_ptr相关的知识,希望对你有一定的参考价值。

部分参考地址https://blog.csdn.net/yanglingwell/article/details/56011576

auto_ptr是c++标准库里的智能指针,但是具有以下几个明显的缺陷,使用时要注意

1.就是所谓的控制权转移,下面是模拟代码

    auto_Ptr(auto_Ptr<T>&ap)
    {
        _ptr = new T;           //先分配空间
        _ptr = ap._ptr;          //再资源转移
        ap._ptr = NULL;        //将原来的指针置空
    }

在赋值运算符重载和拷贝构造函数中将资源转移,来的指针被赋空,要是再进行一些使用的语句那么程序会崩溃

2.不能管理数组

    ~auto_ptr() _NOEXCEPT
        {    // destroy the object
        delete _Myptr;
        }

    

void reset(_Ty *_Ptr = 0)
{ // destroy designated object and store new pointer
if (_Ptr != _Myptr)
delete _Myptr;
_Myptr = _Ptr;
}

 

这是auto_ptr内部析构和重置的代码,如果是数组需要delete[],所以不能完全释放数组的内存

另外分析一下auto_ptr的几个源代码

当我执行下面这句代码时

std::auto_ptr<int>b(auto_ptr<int>(new(int)));

执行顺序如下

 1     explicit auto_ptr(_Ty *_Ptr = 0) _THROW0()
 2         : _Myptr(_Ptr)
 3         {    // construct from object pointer
 4         }
 5         //这个应该起隐式转换的作用
 6        template<class _Other>
 7         operator auto_ptr_ref<_Other>() _THROW0()
 8         {    // convert to compatible auto_ptr_ref
 9         _Other *_Cvtptr = _Myptr;    // test implicit conversion
10         auto_ptr_ref<_Other> _Ans(_Cvtptr);
11         _Myptr = 0;    // pass ownership to auto_ptr_ref
12         return (_Ans);
13         }
14 
15 
16     auto_ptr(auto_ptr_ref<_Ty> _Right) _THROW0()
17         {    // construct by assuming pointer from _Right auto_ptr_ref
18         _Ty *_Ptr = _Right._Ref;
19         _Right._Ref = 0;    // release old
20         _Myptr = _Ptr;    // reset this
21         }
22 
23     ~auto_ptr() _NOEXCEPT
24         {    // destroy the object
25         delete _Myptr;
26         }

对于auto_ptr_ref是什么东西,下面是一段解释(我是没太懂为什么会调用operator auto_ptr_ref<_Other>())

 

Q: what is auto_ptr_ref, what it achieves and how it achieves it ? 

A: It is rather confusing. Basically, auto_ptr_ref exists because the auto_ptr copy constructor isn’t really a copy constructor in the standard sense of the word.

Copy constructors typically have a signature that looks like this:

X(const X &b); 
The auto_ptr copy constructor has a signature that looks like this:

X(X &b) 
This is because auto_ptr needs to modify the object being copied from in order to set its pointer to 0 to facilitate the ownership semantics of auto_ptr.

Sometimes, temporaries cannot match a copy constructor that doesn’t declare its argument const. This is where auto_ptr_ref comes in. The compiler won’t be able to call the non-const version of the copy constructor, but it can call the conversion operator. The conversion operator creates an auto_ptr_ref object that’s just sort of a temporary holder for the pointer. The auto_ptr constructor or operator = is called with the auto_ptr_ref argument.

If you notice, the conversion operator in auto_ptr that automatically converts to an auto_ptr_ref does a release on the source auto_ptr, just like the copy constructor does.

It’s kind of a weird little dance that happens behind the scenes because auto_ptr modifies the thing being copied from.

简单地总结: auto_ptr_ref 主要解决用右值来构造 auto_ptr 的情况。 因为, auto_ptr(auto_ptr& r) 构造函数只能以左值引用做参数。当右值来构造 auto_ptr_ref 的时候,实际上实现过程如下(这其实是移动语义的早期实现版本): 
技术分享图片

 

scoped_ptr类似于auto_ptr但是弥补了它的部分缺陷,scoped_ptr的所有权更加严格,不能转让,一旦scoped_pstr获取了对象的管理权,你就无法再从它那里取回来。

代码实现如下:

template<class T>
class scoped_ptr{
private:
    T *px;
    scoped_ptr(scoped_ptr const &);
    scoped_ptr & operator=(scoped_ptr const &);
public:
    explicit scoped_ptr(T *p = 0);
    ~scoped_ptr();

    void reset(T *p = 0);

    T & operator*()const;
    T * operator->()const;
    T * get()const;

    operator unspecified-bool-type()const;
    void swap(scoped_ptr & b);
};

可见,scoped_str的构造函数接受一个类型为T*的指针p,创建出一个scoped_ptr对象,并在内部保存指针参数p。p必须是一个new表达式动态分配的结果,或者是一个空指针(0)。当scoped_ptr对象的生命周期结束时,析构函数~scoped_ptr()会使用delete操作自动销毁所保存的指针对象,从而正确的回收资源。

scoped_ptr同时把拷贝构造函数和赋值操作都声明为私有的,禁止对智能指针的复制操作,保证了被它管理的指针不能被转让所有权。

最后加一点

!智能指针都应避免的一点:

string vacation("I wandered lonely as a cloud.");
shared_ptr<string> pvac(&vacation);   // No

pvac过期时,程序将把delete运算符用于非堆内存,这是错误的。











以上是关于智能指针之auto_ptr和scoped_ptr的主要内容,如果未能解决你的问题,请参考以下文章

C++智能指针的作用,模拟实现auto_ptr,scoped_ptr,shared_ptr

智能指针:模拟实现auto_ptr,scoped_ptr,shared_ptr

C++智能指针详解:scoped_ptr

C++智能指针详解:shared_ptr

boost智能指针

智能指针之 auto_ptr