神秘的auto_ptr

来源:互联网 发布:mysql create user 编辑:程序博客网 时间:2024/04/30 06:52

作者:winterTTr(转载请注明) 资料来源:《STL标准库》

为什么说它神秘呢,那好吧,我可以换一个更直白的词语,那就是“陷阱重重”。

对于不了解auto_ptr的人来说,使用它就是一种灾难,而避免这种灾难,就必须揭开它神秘的面纱,了解其内部运作机制。


为什么要出现auto_ptr 
view plaincopy to clipboardprint?
void f()   
{   
    ClassA* ptr = new ClassA; //create an object explicitly   
    ...; //perform some operations   
    delete ptr; //clean up (destroy the object explicitly)   
}  

看这样一段代码,如果中间的操作出现异常,或者出现return,我们将会忘记释放ptr这个变量的空间,这无疑会造成内存泄露。而这种泄露往往可能是我们不经意的。那么,auto_ptr的出现,就是为了解决这种问题而出现的。他利用局部变量离开作用域会释放的原则,将主动申请的资源指针放置于其内部,并在其析构的时候,释放掉资源。由于auto_ptr本身是局部变量,就保证了主动申请的资源能够在离开作用域的时候被及时合理的释放。同时,即便是异常的出现,也不会造成内存的泄露。

好, 我们重写上面的代码:

view plaincopy to clipboardprint?
//header file for auto_ptr   
#include <memory>   
void f()   
{   
    //create and initialize an auto_ptr   
    std::auto_ptr<ClassA> ptr(new ClassA);   
    ...; //perform some operations   
}  
//header file for auto_ptr

当然,auto_ptr重载了*和->操作符,我们能像正常使用原始指针一样,去使用这个变量。

使用的注意点:

1.指针的计算操作(例如:++)是没有 被定义的

2.auto_ptr不允许使用原始指针进行赋值操作,只能使用原始指针进行构造函数的初始化。

也就是说:

std::auto_ptr<ClassA> ptr1(new ClassA); //OK
std::auto_ptr<ClassA> ptr2 = new ClassA; //ERROR


auto_ptr的神秘面纱:拥有权的转移 
拥有权(Ownership)是auto_ptr最重要的概念之一。对于一个auto_ptr来说,它会主动释放它所拥有的资源。所以,对于资源的拥有权应该是唯一的。在同一时间,一个资源应该只能被一个auto_ptr所拥有(否则可能会造成double delete的crash)。

那么,涉及到一个很重要的注意点:auto_ptr的拷贝构造函数和赋值操作符,是如何动作的呢。


//initialize an auto_ptr with a new object   
std::auto_ptr<ClassA> ptr1(new ClassA);   
//copy the auto_ptr   
//- transfers ownership from ptr1 to ptr2   
std::auto_ptr<ClassA> ptr2(ptr1);  

看这样的代码,在进行copy construct之后,ClassA的资源,实际上已经被转移到ptr2中了,那么ptr1呢?!这点非常关键(同时所引起的问题也是致命的),ptr1内部,实际上已经是空指针了!!ptr1不在拥有(释放了)对资源的拥有权(保证拥有权的唯一性)。

同理,赋值操作符也是进行同样的操作。这便是auto_ptr最神秘的面纱~~

auto_ptr的在函数调用中的情况 
1. 传值方式的函数调用:会将拥有权传入函数内部,同时函数执行结束后,会释放资源。

2. 返回值方式的函数调用:会将函数申请的资源返回caller,caller退出后,将会释放资源。

注意点 
1.不要随便使用传值方式的auto_ptr函数调用,因为这样会释放你的资源

2.企图使用引用方式的函数调用,可能会在函数内部被赋值操作转移拥有权,这是很不好的调用方式。

3.使用const的引用方式,可以减少无意识的拥有权转移的问题。

4.对于const方式的引用,其实可能更像是一个T* const p,而不是const T* p


有关auto_ptr的使用事项

1.一定不要使用auto_ptr共享一个资源的拥有权

2.不能使用auto_ptr存储数组指针,因为只有auto_ptr执行的是delete对,而不是delete []

3.auto_ptr不是被设计为引用计数的智能指针,所以,不要试图按照这种想法去使用

4.auto_ptr是不能被STL中的标准容器使用的,因为其中的赋值操作,会转移ownership,这会造成意想不到的问题。


auto_ptr的内幕 
namespace std 

{   
    //auxiliary type to enable copies and assignments   
    template <class Y> struct auto_ptr_ref {};   
    template<class T>   
        class auto_ptr 

       {   
            public:   
                //type names for the value   
                typedef T element_type;   
                //constructor   
                explicit auto_ptr(T* ptr = 0) throw();   
                //copy constructors (with implicit conversion)   
                //- note: nonconstant parameter   
                auto_ptr(auto_ptr&) throw();   
                template<class U> auto_ptr(auto_ptr<U>&) throw();   
                //assignments (with implicit conversion)   
                //- note: nonconstant parameter   
                auto_ptr& operator= (auto_ptr&) throw();   
                template<class U>   
                    auto_ptr& operator= (auto_ptr<U>&) throw();   
                //destructor   
                ~auto_ptr() throw();   
                //value access   
                T* get() const throw();   
                T& operator*() const throw();   
                T* operator->() const throw();   
                //release ownership   
                T* release() throw();   
                //reset value   
                void reset(T* ptr = 0) throw();   
                //special conversions to enable copies and assignments   
            public:   
                auto_ptr(auto_ptr_ref<T>) throw();   
                auto_ptr& operator= (auto_ptr_ref<T> rhs) throw();   
                template<class U> operator auto_ptr_ref<U>() throw();   
                template<class U> operator auto_ptr<U>() throw();   
        };   
}  
值得注意的是,reset函数执行的操作,是先delete内部资源,再重新获得新的资源。

get()不改变拥有权,release()会放弃拥有权(赋值NULL)

原创粉丝点击