先放代码
1 /* 2 * Copyright (c) 1997-1999 3 * Silicon Graphics Computer Systems, Inc. 4 * 5 * Permission to use, copy, modify, distribute and sell this software 6 * and its documentation for any purpose is hereby granted without fee, 7 * provided that the above copyright notice appear in all copies and 8 * that both that copyright notice and this permission notice appear 9 * in supporting documentation. Silicon Graphics makes no 10 * representations about the suitability of this software for any 11 * purpose. It is provided "as is" without express or implied warranty. 12 * 13 */ 14 15 #ifndef __SGI_STL_MEMORY 16 #define __SGI_STL_MEMORY 17 18 #include <stl_algobase.h> 19 #include <stl_alloc.h> 20 #include <stl_construct.h> 21 #include <stl_tempbuf.h> 22 #include <stl_uninitialized.h> 23 #include <stl_raw_storage_iter.h> 24 25 26 __STL_BEGIN_NAMESPACE 27 28 #if defined(__SGI_STL_USE_AUTO_PTR_CONVERSIONS) && \ 29 defined(__STL_MEMBER_TEMPLATES) 30 31 template<class _Tp1> struct auto_ptr_ref { 32 _Tp1* _M_ptr; 33 auto_ptr_ref(_Tp1* __p) : _M_ptr(__p) {} 34 }; 35 36 #endif 37 38 template <class _Tp> class auto_ptr { 39 private: 40 _Tp* _M_ptr; 41 42 public: 43 typedef _Tp element_type; 44 45 explicit auto_ptr(_Tp* __p = 0) __STL_NOTHROW : _M_ptr(__p) {} 46 auto_ptr(auto_ptr& __a) __STL_NOTHROW : _M_ptr(__a.release()) {} 47 48 #ifdef __STL_MEMBER_TEMPLATES 49 template <class _Tp1> auto_ptr(auto_ptr<_Tp1>& __a) __STL_NOTHROW 50 : _M_ptr(__a.release()) {} 51 #endif /* __STL_MEMBER_TEMPLATES */ 52 53 auto_ptr& operator=(auto_ptr& __a) __STL_NOTHROW { 54 if (&__a != this) { 55 delete _M_ptr; 56 _M_ptr = __a.release(); 57 } 58 return *this; 59 } 60 61 #ifdef __STL_MEMBER_TEMPLATES 62 template <class _Tp1> 63 auto_ptr& operator=(auto_ptr<_Tp1>& __a) __STL_NOTHROW { 64 if (__a.get() != this->get()) { 65 delete _M_ptr; 66 _M_ptr = __a.release(); 67 } 68 return *this; 69 } 70 #endif /* __STL_MEMBER_TEMPLATES */ 71 72 // Note: The C++ standard says there is supposed to be an empty throw 73 // specification here, but omitting it is standard conforming. Its 74 // presence can be detected only if _Tp::~_Tp() throws, but (17.4.3.6/2) 75 // this is prohibited. 76 ~auto_ptr() { delete _M_ptr; } 77 78 _Tp& operator*() const __STL_NOTHROW { 79 return *_M_ptr; 80 } 81 _Tp* operator->() const __STL_NOTHROW { 82 return _M_ptr; 83 } 84 _Tp* get() const __STL_NOTHROW { 85 return _M_ptr; 86 } 87 _Tp* release() __STL_NOTHROW { 88 _Tp* __tmp = _M_ptr; 89 _M_ptr = 0; 90 return __tmp; 91 } 92 void reset(_Tp* __p = 0) __STL_NOTHROW { 93 if (__p != _M_ptr) { 94 delete _M_ptr; 95 _M_ptr = __p; 96 } 97 } 98 99 // According to the C++ standard, these conversions are required. Most 100 // present-day compilers, however, do not enforce that requirement---and, 101 // in fact, most present-day compilers do not support the language 102 // features that these conversions rely on. 103 104 #if defined(__SGI_STL_USE_AUTO_PTR_CONVERSIONS) && \ 105 defined(__STL_MEMBER_TEMPLATES) 106 107 public: 108 auto_ptr(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW 109 : _M_ptr(__ref._M_ptr) {} 110 111 auto_ptr& operator=(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW { 112 if (__ref._M_ptr != this->get()) { 113 delete _M_ptr; 114 _M_ptr = __ref._M_ptr; 115 } 116 return *this; 117 } 118 119 template <class _Tp1> operator auto_ptr_ref<_Tp1>() __STL_NOTHROW 120 { return auto_ptr_ref<_Tp1>(this->release()); } 121 template <class _Tp1> operator auto_ptr<_Tp1>() __STL_NOTHROW 122 { return auto_ptr<_Tp1>(this->release()); } 123 124 #endif /* auto ptr conversions && member templates */ 125 }; 126 127 __STL_END_NAMESPACE 128 129 #endif /* __SGI_STL_MEMORY */ 130 131 132 // Local Variables: 133 // mode:C++ 134 // End:
auto_ptr是资源持有型的指针工具,只支持自动释放功能。需要注意的是
1. 不要多个auto_ptr共同支持有一个资源。
2.不要对被赋值后的auto_ptr引用,那样将非法无效。
3.auto_ptr不是copyable对象,所以不要在容器中使用。
4.auto_ptr不支持数组形式。
首先说明关于auto_ptr_ref放在最后再说~
私有数据域,只有一个即_M_ptr指针。
然后轻量级抽象数据类型(STL商用手法)。
typedef _Tp element_type.
第一个构造函数
explicit auto_ptr(_Tp* __p = 0) __STL_NOTHROW : _M_ptr(__p) {}
注意技巧:
1. explicit防止了,不必要的隐式数据转换。
2. 加上了默认参数,这样允许无参数构造。
3.__STL_NOTHROW 其实就是 throw().注意此处作用,只是告诉调用者,该函数不会抛出异常,而实现者需要注意不要在此抛出异常。
第二个构造函数
auto_ptr(auto_ptr& __a) __STL_NOTHROW : _M_ptr(__a.release()) {}
由于是资源持有型的特点,所以参数需要释放持有权,向资源传给当前指针。
然后是member template的构造函数。
#ifdef __STL_MEMBER_TEMPLATES
template <class _Tp1> auto_ptr(auto_ptr<_Tp1>& __a) __STL_NOTHROW
: _M_ptr(__a.release()) {}
前提是编译器支持这种功能。关于member template,我在pair的伤心中又提到过。
然后是2个赋值重载,第二个也是member template的。
auto_ptr& operator=(auto_ptr& __a) __STL_NOTHROW {
if (&__a != this) {
delete _M_ptr;
_M_ptr = __a.release();
}
return *this;
}
#ifdef __STL_MEMBER_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 */
注意事项:
1.两者的不同,前者是判断引用两者地址是否相同,后者是判断两者引用对象是否相同。//这里没太明白区别两者的作用。
2.赋值前,要释放原有资源,防止内存泄漏。
3.返回该对象引用(operator = 要求)。
然后是几个非常naive,非常易懂的函数。
~auto_ptr() { delete _M_ptr; }
_Tp& operator*() const __STL_NOTHROW {
return *_M_ptr;
}
_Tp* operator->() const __STL_NOTHROW {
return _M_ptr;
}
_Tp* get() const __STL_NOTHROW {
return _M_ptr;
}
_Tp* release() __STL_NOTHROW {
_Tp* __tmp = _M_ptr;
_M_ptr = 0;
return __tmp;
}
void reset(_Tp* __p = 0) __STL_NOTHROW {
if (__p != _M_ptr) {
delete _M_ptr;
_M_ptr = __p;
}
}
特别需要注意的是:
1.是用release函数,该指针释只放了资源的持有权,并没有释放资源,所以请注意,如果release到一个指针上,请注意自己释放资源。
2.reset函数 至于判断当前持有资源和要reset的资源是否相等,如果相等,不要释放,否则会出错。
接下来是几个member template函数。
public:
auto_ptr(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW
: _M_ptr(__ref._M_ptr) {}
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;
}
template <class _Tp1> operator auto_ptr_ref<_Tp1>() __STL_NOTHROW
{ return auto_ptr_ref<_Tp1>(this->release()); }
template <class _Tp1> operator auto_ptr<_Tp1>() __STL_NOTHROW
{ return auto_ptr<_Tp1>(this->release()); }
#endif /* auto ptr conversions && member templates */
其中包括了 auto_ptr_ref的转换等重要工作。
我们先看看auto_ptr_ref的定义。
非常轻量简单,也非常使用。
template<class _Tp1> struct auto_ptr_ref {
_Tp1* _M_ptr;
auto_ptr_ref(_Tp1* __p) : _M_ptr(__p) {}
};
只有一个指针域指向对应的auto_ptr。
但是注意,该函数没有指定一定要指向auto_ptr……
如果仔细看一下第二个构造函数,我们发现 他不是拷贝构造函数!因为少了一个const,因为auto_ptr的定义资源持有型,所以该函数不可以又传统的(const&)的拷贝构造函数。而非常量引用不能绑定右值,这样就导致auto_ptr的语义缺失。
众所周知,没有优质绑定将导致一系列的语法不能使用。
例如说:
auto_ptr<int> f();
auto_ptr ptr(f())无法使用。诸如此类的问题。
所以就提出了auto_ptr_ref,他的工作方式就是提供一个间接转换过程,从auto_ptr到auto_ptr_ref到auto_ptr.
于是乎,便又一个上述的隐式类型转换。
我们以
auto_ptr<int> f();
auto_ptr ptr(f())为例,简单说明一下auto_ptr_ref的工作原理。
f() 返回一个一个auto_ptr但是由于 auto_ptr的没有const 拷贝构造函数,没法进行右值引用,而有
auto_ptr(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW
: _M_ptr(__ref._M_ptr) {}
以及
template <class _Tp1> operator auto_ptr_ref<_Tp1>() __STL_NOTHROW
{ return auto_ptr_ref<_Tp1>(this->release()); }
所以完成了一次右值转换。从右值只有的资源释放给auto_ptr_ref,auto_ptr_ref存在在堆栈中,右值auto_ptr销毁。
调用匹配的构造函数auto_ptr(auto_ptr_ref<_Tp> __ref),完成资源转让,完成构造。
该方式十分cool,十分巧妙。非常间接的解决了右值引用的问题。