程序人生 >> STL auto_ptr智能指針簡單分析: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智能指針簡單分析
作者:代碼瘋子