STL auto_ptr智能指针简单分析
本文出自程序人生 >> STL auto_ptr智能指针简单分析
闲着没事,整理一下对auto_ptr的理解。去年年底的时候准备认认真真的看看STL源代码,可是时间不是很充足,自己也不是很坚定,于是就乱七八糟的看了看。现在虽然琐事繁多,但时间还是有的,所以再整理下。
auto_ptr是STL里面的智能指针(Smart Pointer),一个很好的优点就是指针所有权自动转移和指针自动删除技术。对于异常和经常忘记delete的情况来说很实用。下面就是从SGI官方网站下载的STL auto_ptr实现源码(加上了我的注释):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
/* * Copyright (c) 1997-1999 * Silicon Graphics Computer Systems, Inc. * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Silicon Graphics makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * */ #ifndef __SGI_STL_MEMORY #define __SGI_STL_MEMORY #include <stl_algobase.h> #include <stl_alloc.h> #include <stl_construct.h> #include <stl_tempbuf.h> #include <stl_uninitialized.h> #include <stl_raw_storage_iter.h> __STL_BEGIN_NAMESPACE // 如果定义了auto_ptr转换以及支持成员函数模板 #if defined(__SGI_STL_USE_AUTO_PTR_CONVERSIONS) && \ defined(__STL_MEMBER_TEMPLATES) // 定义auto_ptr_ref template结构体① template<class _Tp1> struct auto_ptr_ref { _Tp1* _M_ptr; auto_ptr_ref(_Tp1* __p) : _M_ptr(__p) {} }; #endif template <class _Tp> class auto_ptr { private: _Tp* _M_ptr; public: typedef _Tp element_type; // explicit修饰构造函数,防止从原始指针隐式转换 explicit auto_ptr(_Tp* __p = 0) __STL_NOTHROW : _M_ptr(__p) {} // Copy构造函数,注意这里是直接引用传参(非const),同时转移指针所有权 auto_ptr(auto_ptr& __a) __STL_NOTHROW : _M_ptr(__a.release()) {} // 如果允许定义成员函数模板(Member Function Templates)② #ifdef __STL_MEMBER_TEMPLATES // 如果可以从_Tp1*转换为_Tp*,则可以从auto_ptr<_Tp1>构造auto_ptr<_Tp> // 同时转移指针所有权 template <class _Tp1> auto_ptr(auto_ptr<_Tp1>& __a) __STL_NOTHROW : _M_ptr(__a.release()) {} #endif /* __STL_MEMBER_TEMPLATES */ // 赋值操作符,同样是非const引用传参,有证同测试③ auto_ptr& operator=(auto_ptr& __a) __STL_NOTHROW { // 如果是自我赋值,就直接返回 if (&__a != this) { delete _M_ptr; _M_ptr = __a.release(); } return *this; } #ifdef __STL_MEMBER_TEMPLATES // 赋值操作符的Member Function Templates template <class _Tp1> auto_ptr& operator=(auto_ptr<_Tp1>& __a) __STL_NOTHROW { if (__a.get() != this->get()) { delete _M_ptr; _M_ptr = __a.release(); } return *this; } #endif /* __STL_MEMBER_TEMPLATES */ // Note: The C++ standard says there is supposed to be an empty throw // specification here, but omitting it is standard conforming. Its // presence can be detected only if _Tp::~_Tp() throws, but (17.4.3.6/2) // this is prohibited. // auto_ptr的析构函数 ~auto_ptr() { delete _M_ptr; } // operator*定义,返回值 _Tp& operator*() const __STL_NOTHROW { return *_M_ptr; } // operator->定义,返回指针 _Tp* operator->() const __STL_NOTHROW { return _M_ptr; } // const成员函数get定义,返回指针 _Tp* get() const __STL_NOTHROW { return _M_ptr; } // release函数定义,释放指针 _Tp* release() __STL_NOTHROW { _Tp* __tmp = _M_ptr; _M_ptr = 0; return __tmp; } // reset函数定义,重置指针 void reset(_Tp* __p = 0) __STL_NOTHROW { if (__p != _M_ptr) { delete _M_ptr; _M_ptr = __p; } } // According to the C++ standard, these conversions are required. Most // present-day compilers, however, do not enforce that requirement---and, // in fact, most present-day compilers do not support the language // features that these conversions rely on. #if defined(__SGI_STL_USE_AUTO_PTR_CONVERSIONS) && \ defined(__STL_MEMBER_TEMPLATES) public: // 从auto_ptr_ref<_Tp>构造auto_ptr<_Tp> auto_ptr(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW : _M_ptr(__ref._M_ptr) {} // 从auto_ptr_ref<_Tp>对auto_ptr<_Tp>进行赋值操作。 // 注意这里是普通传参,没有引用④ auto_ptr& operator=(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW { if (__ref._M_ptr != this->get()) { delete _M_ptr; _M_ptr = __ref._M_ptr; } return *this; } // 成员函数模板(Member Function Templates)② // 如果可以从_Tp*转换为_Tp1*,则可以从auto_ptr<_Tp>转换为auto_ptr_ref<_Tp1> template <class _Tp1> operator auto_ptr_ref<_Tp1>() __STL_NOTHROW { return auto_ptr_ref<_Tp1>(this->release()); } // 成员函数模板(Member Function Templates)② // 如果可以从_Tp*转换为_Tp1*,则可以从auto_ptr<_Tp>转换为auto_ptr<_Tp1> template <class _Tp1> operator auto_ptr<_Tp1>() __STL_NOTHROW { return auto_ptr<_Tp1>(this->release()); } #endif /* auto ptr conversions && member templates */ }; __STL_END_NAMESPACE #endif /* __SGI_STL_MEMORY */ // Local Variables: // mode:C++ // End: |
注解:
①auto_ptr_ref结构体
我们看到,auto_ptr源代码中的Copy构造函数的参数是普通的引用传参(不是const引用,也不是普通的传值),这是为了方便指针拥有权的转移(如果是const引用,那么拥有权无法转移;如果是普通的传值,oh my god,整个世界都彻底混乱了)。那如果以一个临时对象(也就是所谓的右值)进行拷贝构造,那样就无法通过编译了(普通指针或引用不能指向const对象,即不能指向右值)。幸好有auto_ptr_ref的存在,可以从auto_ptr_ref临时对象构造或者赋值为auto_ptr对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public: // 从auto_ptr_ref<_Tp>构造auto_ptr<_Tp> auto_ptr(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW : _M_ptr(__ref._M_ptr) {} // 从auto_ptr_ref<_Tp>对auto_ptr<_Tp>进行赋值操作。 // 注意这里是普通传参,没有引用④ auto_ptr& operator=(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW { if (__ref._M_ptr != this->get()) { delete _M_ptr; _M_ptr = __ref._M_ptr; } return *this; } |
而auto_ptr对象也可以隐式的转化为auto_ptr_ref类型的对象:
1 2 |
template <class _Tp1> operator auto_ptr_ref<_Tp1>() __STL_NOTHROW { return auto_ptr_ref<_Tp1>(this->release()); } |
于是乎,就完美的完成了auto_ptr从右值到左值的转换工作。也可以看这里:为什么需要auto_ptr_ref
②成员函数模板(Member Function Templates)
③证同测试,见《Effective C++》条款11:在operator= 中处理“自我赋值” (Item 11. handle assignment to self in operator=)
④见①
原创文章,转载请注明:
本文出自程序人生 >> STL auto_ptr智能指针简单分析
作者:代码疯子