今晚跟同学谈了一下智能指针,突然想要看一下C++11的智能指针的实现,因此下了这篇博文。
以下代码出自于VS2012 <memory>
001.
template
<
class
_Ty>
002.
class
shared_ptr
003.
:
public
_Ptr_base<_Ty>
004.
{
// class for reference counted resource management
005.
public
:
006.
typedef
shared_ptr<_Ty> _Myt;
007.
typedef
_Ptr_base<_Ty> _Mybase;
008.
009.
shared_ptr() _NOEXCEPT
010.
{
// construct empty shared_ptr object
011.
}
012.
013.
template
<
class
_Ux>
014.
explicit
shared_ptr(_Ux *_Px)
015.
{
// construct shared_ptr object that owns _Px
016.
_Resetp(_Px);
017.
}
018.
019.
template
<
class
_Ux,
020.
class
_Dx>
021.
shared_ptr(_Ux *_Px, _Dx _Dt)
022.
{
// construct with _Px, deleter
023.
_Resetp(_Px, _Dt);
024.
}
025.
026.
//#if _HAS_CPP0X
027.
028.
shared_ptr(nullptr_t)
029.
{
// construct with nullptr
030.
_Resetp((_Ty *)0);
031.
}
032.
033.
template
<
class
_Dx>
034.
shared_ptr(nullptr_t, _Dx _Dt)
035.
{
// construct with nullptr, deleter
036.
_Resetp((_Ty *)0, _Dt);
037.
}
038.
039.
template
<
class
_Dx,
040.
class
_Alloc>
041.
shared_ptr(nullptr_t, _Dx _Dt, _Alloc _Ax)
042.
{
// construct with nullptr, deleter, allocator
043.
_Resetp((_Ty *)0, _Dt, _Ax);
044.
}
045.
046.
template
<
class
_Ux,
047.
class
_Dx,
048.
class
_Alloc>
049.
shared_ptr(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
050.
{
// construct with _Px, deleter, allocator
051.
_Resetp(_Px, _Dt, _Ax);
052.
}
053.
//#endif /* _HAS_CPP0X */
054.
055.
#if _HAS_CPP0X
056.
template
<
class
_Ty2>
057.
shared_ptr(
const
shared_ptr<_Ty2>& _Right, _Ty *_Px) _NOEXCEPT
058.
{
// construct shared_ptr object that aliases _Right
059.
this
->_Reset(_Px, _Right);
060.
}
061.
#endif /* _HAS_CPP0X */
062.
063.
shared_ptr(
const
_Myt& _Other) _NOEXCEPT
064.
{
// construct shared_ptr object that owns same resource as _Other
065.
this
->_Reset(_Other);
066.
}
067.
068.
template
<
class
_Ty2>
069.
shared_ptr(
const
shared_ptr<_Ty2>& _Other,
070.
typename
enable_if<is_convertible<_Ty2 *, _Ty *>::value,
071.
void
>::type ** = 0) _NOEXCEPT
072.
{
// construct shared_ptr object that owns same resource as _Other
073.
this
->_Reset(_Other);
074.
}
075.
076.
template
<
class
_Ty2>
077.
explicit
shared_ptr(
const
weak_ptr<_Ty2>& _Other,
078.
bool
_Throw =
true
)
079.
{
// construct shared_ptr object that owns resource *_Other
080.
this
->_Reset(_Other, _Throw);
081.
}
082.
083.
template
<
class
_Ty2>
084.
shared_ptr(auto_ptr<_Ty2>&& _Other)
085.
{
// construct shared_ptr object that owns *_Other.get()
086.
this
->_Reset(_STD move(_Other));
087.
}
088.
089.
template
<
class
_Ty2>
090.
shared_ptr(
const
shared_ptr<_Ty2>& _Other,
const
_Static_tag& _Tag)
091.
{
// construct shared_ptr object for static_pointer_cast
092.
this
->_Reset(_Other, _Tag);
093.
}
094.
095.
template
<
class
_Ty2>
096.
shared_ptr(
const
shared_ptr<_Ty2>& _Other,
const
_Const_tag& _Tag)
097.
{
// construct shared_ptr object for const_pointer_cast
098.
this
->_Reset(_Other, _Tag);
099.
}
100.
101.
template
<
class
_Ty2>
102.
shared_ptr(
const
shared_ptr<_Ty2>& _Other,
const
_Dynamic_tag& _Tag)
103.
{
// construct shared_ptr object for dynamic_pointer_cast
104.
this
->_Reset(_Other, _Tag);
105.
}
106.
107.
shared_ptr(_Myt&& _Right) _NOEXCEPT
108.
: _Mybase(_STD forward<_Myt>(_Right))
109.
{
// construct shared_ptr object that takes resource from _Right
110.
}
111.
112.
template
<
class
_Ty2>
113.
shared_ptr(shared_ptr<_Ty2>&& _Right,
114.
typename
enable_if<is_convertible<_Ty2 *, _Ty *>::value,
115.
void
>::type ** = 0) _NOEXCEPT
116.
: _Mybase(_STD forward<shared_ptr<_Ty2> >(_Right))
117.
{
// construct shared_ptr object that takes resource from _Right
118.
}
119.
120.
#if _HAS_CPP0X
121.
template
<
class
_Ux,
122.
class
_Dx>
123.
shared_ptr(unique_ptr<_Ux, _Dx>&& _Right)
124.
{
// construct from unique_ptr
125.
_Resetp(_Right.release(), _Right.get_deleter());
126.
}
127.
128.
template
<
class
_Ux,
129.
class
_Dx>
130.
_Myt& operator=(unique_ptr<_Ux, _Dx>&& _Right)
131.
{
// move from unique_ptr
132.
shared_ptr(_STD move(_Right)).swap(*
this
);
133.
return
(*
this
);
134.
}
135.
#endif /* _HAS_CPP0X */
136.
137.
_Myt& operator=(_Myt&& _Right) _NOEXCEPT
138.
{
// construct shared_ptr object that takes resource from _Right
139.
shared_ptr(_STD move(_Right)).swap(*
this
);
140.
return
(*
this
);
141.
}
142.
143.
template
<
class
_Ty2>
144.
_Myt& operator=(shared_ptr<_Ty2>&& _Right) _NOEXCEPT
145.
{
// construct shared_ptr object that takes resource from _Right
146.
shared_ptr(_STD move(_Right)).swap(*
this
);
147.
return
(*
this
);
148.
}
149.
150.
~shared_ptr() _NOEXCEPT
151.
{
// release resource
152.
this
->_Decref();
153.
}
154.
155.
_Myt& operator=(
const
_Myt& _Right) _NOEXCEPT
156.
{
// assign shared ownership of resource owned by _Right
157.
shared_ptr(_Right).swap(*
this
);
158.
return
(*
this
);
159.
}
160.
161.
template
<
class
_Ty2>
162.
_Myt& operator=(
const
shared_ptr<_Ty2>& _Right) _NOEXCEPT
163.
{
// assign shared ownership of resource owned by _Right
164.
shared_ptr(_Right).swap(*
this
);
165.
return
(*
this
);
166.
}
167.
168.
template
<
class
_Ty2>
169.
_Myt& operator=(auto_ptr<_Ty2>&& _Right)
170.
{
// assign ownership of resource pointed to by _Right
171.
shared_ptr(_STD move(_Right)).swap(*
this
);
172.
return
(*
this
);
173.
}
174.
175.
void
reset() _NOEXCEPT
176.
{
// release resource and convert to empty shared_ptr object
177.
shared_ptr().swap(*
this
);
178.
}
179.
180.
template
<
class
_Ux>
181.
void
reset(_Ux *_Px)
182.
{
// release, take ownership of _Px
183.
shared_ptr(_Px).swap(*
this
);
184.
}
185.
186.
template
<
class
_Ux,
187.
class
_Dx>
188.
void
reset(_Ux *_Px, _Dx _Dt)
189.
{
// release, take ownership of _Px, with deleter _Dt
190.
shared_ptr(_Px, _Dt).swap(*
this
);
191.
}
192.
193.
//#if _HAS_CPP0X
194.
template
<
class
_Ux,
195.
class
_Dx,
196.
class
_Alloc>
197.
void
reset(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
198.
{
// release, take ownership of _Px, with deleter _Dt, allocator _Ax
199.
shared_ptr(_Px, _Dt, _Ax).swap(*
this
);
200.
}
201.
//#endif /* _HAS_CPP0X */
202.
203.
void
swap(_Myt& _Other) _NOEXCEPT
204.
{
// swap pointers
205.
this
->_Swap(_Other);
206.
}
207.
208.
_Ty *get()
const
_NOEXCEPT
209.
{
// return pointer to resource
210.
return
(
this
->_Get());
211.
}
212.
213.
typename
add_reference<_Ty>::type operator*()
const
_NOEXCEPT
214.
{
// return reference to resource
215.
return
(*
this
->_Get());
216.
}
217.
218.
_Ty *operator->()
const
_NOEXCEPT
219.
{
// return pointer to resource
220.
return
(
this
->_Get());
221.
}
222.
223.
bool
unique()
const
_NOEXCEPT
224.
{
// return true if no other shared_ptr object owns this resource
225.
return
(
this
->use_count() == 1);
226.
}
227.
228.
_TYPEDEF_BOOL_TYPE;
229.
230.
_OPERATOR_BOOL()
const
_NOEXCEPT
231.
{
// test if shared_ptr object owns no resource
232.
return
(
this
->_Get() != 0 ? _CONVERTIBLE_TO_TRUE : 0);
233.
}
234.
235.
private
:
236.
template
<
class
_Ux>
237.
void
_Resetp(_Ux *_Px)
238.
{
// release, take ownership of _Px
239.
_TRY_BEGIN
// allocate control block and reset
240.
_Resetp0(_Px,
new
_Ref_count<_Ux>(_Px));
241.
_CATCH_ALL
// allocation failed, delete resource
242.
delete
_Px;
243.
_RERAISE;
244.
_CATCH_END
245.
}
246.
247.
template
<
class
_Ux,
248.
class
_Dx>
249.
void
_Resetp(_Ux *_Px, _Dx _Dt)
250.
{
// release, take ownership of _Px, deleter _Dt
251.
_TRY_BEGIN
// allocate control block and reset
252.
_Resetp0(_Px,
new
_Ref_count_del<_Ux, _Dx>(_Px, _Dt));
253.
_CATCH_ALL
// allocation failed, delete resource
254.
_Dt(_Px);
255.
_RERAISE;
256.
_CATCH_END
257.
}
258.
259.
//#if _HAS_CPP0X
260.
template
<
class
_Ux,
261.
class
_Dx,
262.
class
_Alloc>
263.
void
_Resetp(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
264.
{
// release, take ownership of _Px, deleter _Dt, allocator _Ax
265.
typedef
_Ref_count_del_alloc<_Ux, _Dx, _Alloc> _Refd;
266.
typename
_Alloc::
template
rebind<_Refd>::other _Al = _Ax;
267.
268.
_TRY_BEGIN
// allocate control block and reset
269.
_Refd *_Ptr = _Al.allocate(1);
270.
::
new
(_Ptr) _Refd(_Px, _Dt, _Al);
271.
_Resetp0(_Px, _Ptr);
272.
_CATCH_ALL
// allocation failed, delete resource
273.
_Dt(_Px);
274.
_RERAISE;
275.
_CATCH_END
276.
}
277.
//#endif /* _HAS_CPP0X */
278.
279.
public
:
280.
template
<
class
_Ux>
281.
void
_Resetp0(_Ux *_Px, _Ref_count_base *_Rx)
282.
{
// release resource and take ownership of _Px
283.
this
->_Reset0(_Px, _Rx);
284.
_Enable_shared(_Px, _Rx);
285.
}
286.
};
我们可以看到shared_ptr是继承于_Ptr_base的,(同时weak_ptr也继承与_Ptr_base)
那么我们先来看一下_Ptr_base里有什么东西
首先我们可以看到_Ptr_base里面有两个属性
1.
private
:
2.
_Ty *_Ptr;
3.
_Ref_count_base *_Rep;
从shared_ptr我们知道_Ptr_base是个模板,而_Ty是传到_Ptr_base里的模板参数,也就是指针的类型
所以我们知道 _Ptr 保存的值就是真正的指针
但是 _Ref_count_base *_Rep 是什么东西呢,很明显就是引用计数。为什么要用指针呢,因为拥有相同_Ptr值的智能指针要拥有同一个引用计数,因此 _Rep 必须为指针。我们把引用计数类_Ref_count_base 放到后面去讨论。
我们继续看一下shared_ptr的源码可以发现shared_ptr没有显式调用_Ptr_base的构造函数,这意味着shared_ptr只调用_Ptr_base的默认构造函数,但是
shared_ptr的构造函数里大量的调用了两个函数 _Resetp 和 _Reset。
------------------------------------------------------------ _Ptr_base的构造函数 -------------------------------------------------------------------
我们先看一下_Ptr_base的构造函数
01.
_Ptr_base()
02.
: _Ptr(
0
), _Rep(
0
)
03.
{
// construct
04.
}
05.
06.
_Ptr_base(_Myt&& _Right)
07.
: _Ptr(
0
), _Rep(
0
)
08.
{
// construct _Ptr_base object that takes resource from _Right
09.
_Assign_rv(_STD forward<_Myt>(_Right));
10.
}
11.
12.
template<
class
_Ty2>
13.
_Ptr_base(_Ptr_base<_Ty2>&& _Right)
14.
: _Ptr(_Right._Ptr), _Rep(_Right._Rep)
15.
{
// construct _Ptr_base object that takes resource from _Right
16.
_Right._Ptr =
0
;
17.
_Right._Rep =
0
;
18.
}
_Ptr_base的默认构造函数是指针置位nullptr,这没什么好说的。剩下两个是转移构造函数,比较奇怪的是
1.
template<
class
_Ty2>
2.
_Ptr_base(_Ptr_base<_Ty2>&& _Right)
接受以任意类型作为模板参数的_Ptr_base?不懂,估计与shared_ptr向上转型有关。
------------------------------------------------------------ _Ptr_base的_Resetp函数 -------------------------------------------------------------
然后我们看一下_Resetp函数
01.
template<
class
_Ux>
02.
void
_Resetp(_Ux *_Px)
03.
{
// release, take ownership of _Px
04.
_TRY_BEGIN
// allocate control block and reset
05.
_Resetp0(_Px,
new
_Ref_count<_Ux>(_Px));
06.
_CATCH_ALL
// allocation failed, delete resource
07.
delete _Px;
08.
_RERAISE;
09.
_CATCH_END
10.
}
11.
12.
template<
class
_Ux,
13.
class
_Dx>
14.
void
_Resetp(_Ux *_Px, _Dx _Dt)
15.
{
// release, take ownership of _Px, deleter _Dt
16.
_TRY_BEGIN
// allocate control block and reset
17.
_Resetp0(_Px,
new
_Ref_count_del<_Ux, _Dx>(_Px, _Dt));
18.
_CATCH_ALL
// allocation failed, delete resource
19.
_Dt(_Px);
20.
_RERAISE;
21.
_CATCH_END
22.
}
23.
24.
//#if _HAS_CPP0X
25.
template<
class
_Ux,
26.
class
_Dx,
27.
class
_Alloc>
28.
void
_Resetp(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
29.
{
// release, take ownership of _Px, deleter _Dt, allocator _Ax
30.
typedef _Ref_count_del_alloc<_Ux, _Dx, _Alloc> _Refd;
31.
typename _Alloc::template rebind<_Refd>::other _Al = _Ax;
32.
33.
_TRY_BEGIN
// allocate control block and reset
34.
_Refd *_Ptr = _Al.allocate(
1
);
35.
::
new
(_Ptr) _Refd(_Px, _Dt, _Al);
36.
_Resetp0(_Px, _Ptr);
37.
_CATCH_ALL
// allocation failed, delete resource
38.
_Dt(_Px);
39.
_RERAISE;
40.
_CATCH_END
41.
}
_Resetp函数有三个重载,实际上就是 是否带析构器_Dx 和 是否带构造器_Alloc, 这两个参数都用于引用计数,我们继续留到后面讨论。
_Resetp函数的三个重载里又都调用了_Resetp0
1.
template<
class
_Ux>
2.
void
_Resetp0(_Ux *_Px, _Ref_count_base *_Rx)
3.
{
// release resource and take ownership of _Px
4.
this
->_Reset0(_Px, _Rx);
5.
_Enable_shared(_Px, _Rx);
6.
}
这里又调用了父类_Ptr_base的_Reset0 和另一个函数_Enable_shared
先看一下_Reset0
1.
void
_Reset0(_Ty *_Other_ptr, _Ref_count_base *_Other_rep)
2.
{
// release resource and take new resource
3.
if
(_Rep !=
0
)
4.
_Rep->_Decref();
5.
_Rep = _Other_rep;
6.
_Ptr = _Other_ptr;
7.
}
就是检查一下当前_Ptr_base引用计数指针是否为空,非空就释放一个引用计数,然后更新指针值和引用计数值
(为什么叫_Reset0? 0表示最基本的Reset?)
再看一下_Enable_shared
01.
template<
class
_Ty>
02.
inline
void
_Enable_shared(_Ty *_Ptr, _Ref_count_base *_Refptr,
03.
typename _Ty::_EStype * =
0
)
04.
{
// reset internal weak pointer
05.
if
(_Ptr)
06.
_Do_enable(_Ptr,
07.
(enable_shared_from_this<typename _Ty::_EStype>*)_Ptr, _Refptr);
08.
}
09.
10.
inline
void
_Enable_shared(
const
volatile
void
*,
const
volatile
void
*)
11.
{
// not derived from enable_shared_from_this; do nothing
12.
}
这里用了模板的最特化匹配
当_Ty有定义_EStype这个类型名的时候(也就是_Ty继承于enable_shared_from_this<_Ty>的时候)会调用第一个函数。
这里我简单描述一下_Do_enable的作用:
因为_Ty继承于enable_shared_from_this<typename _Ty::_EStype>(实际上_Ty::_EStype就是_Ty,有兴趣的朋友可以去看一下 enable_shared_from_this的源码),enable_shared_from_this<typename _Ty::_EStype>内部保存着一个weak_ptr<_Ty>的弱指针,而_Do_enable的作用就是更新一下这个弱指针的值(使用过shared_ptr的朋友都应该知道enable_shared_from_this是用于共享this指针,而这个共享this指针的操作就是通过这个weak_ptr达到的)。
------------------------------------------------------------ shared_ptr的构造函数 -------------------------------------------------------------
接着我们看一下shared_ptr的调用了_reset的构造函数
01.
1
shared_ptr(
const
_Myt& _Other) _NOEXCEPT
02.
2
{
// construct shared_ptr object that owns same resource as _Other
03.
3
this
->_Reset(_Other);
04.
4
}
05.
5
06.
6
template<
class
_Ty2>
07.
7
shared_ptr(
const
shared_ptr<_Ty2>& _Other,
08.
8
typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
09.
9
void
>::type ** =
0
) _NOEXCEPT
10.
10
{
// construct shared_ptr object that owns same resource as _Other
11.
11
this
->_Reset(_Other);
12.
12
}
13.
13
14.
14
template<
class
_Ty2>
15.
15
explicit shared_ptr(
const
weak_ptr<_Ty2>& _Other,
16.
16
bool _Throw =
true
)
17.
17
{
// construct shared_ptr object that owns resource *_Other
18.
18
this
->_Reset(_Other, _Throw);
19.
19
}
20.
20
21.
21
template<
class
_Ty2>
22.
22
shared_ptr(auto_ptr<_Ty2>&& _Other)
23.
23
{
// construct shared_ptr object that owns *_Other.get()
24.
24
this
->_Reset(_STD move(_Other));
25.
25
}
26.
26
27.
27
template<
class
_Ty2>
28.
28
shared_ptr(
const
shared_ptr<_Ty2>& _Other,
const
_Static_tag& _Tag)
29.
29
{
// construct shared_ptr object for static_pointer_cast
30.
30
this
->_Reset(_Other, _Tag);
31.
31
}
32.
32
33.
33
template<
class
_Ty2>
34.
34
shared_ptr(
const
shared_ptr<_Ty2>& _Other,
const
_Const_tag& _Tag)
35.
35
{
// construct shared_ptr object for const_pointer_cast
36.
36
this
->_Reset(_Other, _Tag);
37.
37
}
38.
38
39.
39
template<
class
_Ty2>
40.
40
shared_ptr(
const
shared_ptr<_Ty2>& _Other,
const
_Dynamic_tag& _Tag)
41.
41
{
// construct shared_ptr object for dynamic_pointer_cast
42.
42
this
->_Reset(_Other, _Tag);
43.
43
}
这里又用到了模板的最特化匹配,注意L1 - L12
1.
is_convertible<_Ty2 *, _Ty *>::value
是C++11提供的一个类型测试模板,用于测试_Ty2 * 与 _Ty *之间是否有合法转换。当有的时候将调用函数L6 - L12,否则调用L1 - L4
这也是shared_ptr<_Ty>可以向shared_ptr<_Ty的父类>向上转型的秘密。
PS:注意shared_ptr还有一个转移构造函数与上面提到的_Ptr_base的转移构造函数相对应
1.
1
template<
class
_Ty2>
2.
2
shared_ptr(shared_ptr<_Ty2>&& _Right,
3.
3
typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
4.
4
void
>::type ** =
0
) _NOEXCEPT
5.
5
: _Mybase(_STD forward<shared_ptr<_Ty2> >(_Right))
6.
6
{
// construct shared_ptr object that takes resource from _Right
7.
7
}
然后L27 - L43的三个构造函数分别用于static_cast、const_cast、dynamic_cast转型。
转型函数见
01.
template<
class
_Ty1,
02.
class
_Ty2>
03.
shared_ptr<_Ty1>
04.
static_pointer_cast(
const
shared_ptr<_Ty2>& _Other) _NOEXCEPT
05.
{
// return shared_ptr object holding static_cast<_Ty1 *>(_Other.get())
06.
return
(shared_ptr<_Ty1>(_Other, _Static_tag()));
07.
}
08.
09.
template<
class
_Ty1,
10.
class
_Ty2>
11.
shared_ptr<_Ty1>
12.
const_pointer_cast(
const
shared_ptr<_Ty2>& _Other) _NOEXCEPT
13.
{
// return shared_ptr object holding const_cast<_Ty1 *>(_Other.get())
14.
return
(shared_ptr<_Ty1>(_Other, _Const_tag()));
15.
}
16.
17.
template<
class
_Ty1,
18.
class
_Ty2>
19.
shared_ptr<_Ty1>
20.
dynamic_pointer_cast(
const
shared_ptr<_Ty2>& _Other) _NOEXCEPT
21.
{
// return shared_ptr object holding dynamic_cast<_Ty1 *>(_Other.get())
22.
return
(shared_ptr<_Ty1>(_Other, _Dynamic_tag()));
23.
}
------------------------------------------------------------ _Ptr_base的_Reset函数 -------------------------------------------------------------
我们最后我们看一下_Ptr_base的_Reset函数
01.
1
void
_Reset()
02.
2
{
// release resource
03.
3
_Reset(
0
,
0
);
04.
4
}
05.
5
06.
6
template<
class
_Ty2>
07.
7
void
_Reset(
const
_Ptr_base<_Ty2>& _Other)
08.
8
{
// release resource and take ownership of _Other._Ptr
09.
9
_Reset(_Other._Ptr, _Other._Rep);
10.
10
}
11.
11
12.
12
template<
class
_Ty2>
13.
13
void
_Reset(
const
_Ptr_base<_Ty2>& _Other, bool _Throw)
14.
14
{
// release resource and take ownership from weak_ptr _Other._Ptr
15.
15
_Reset(_Other._Ptr, _Other._Rep, _Throw);
16.
16
}
17.
17
18.
18
template<
class
_Ty2>
19.
19
void
_Reset(
const
_Ptr_base<_Ty2>& _Other,
const
_Static_tag&)
20.
20
{
// release resource and take ownership of _Other._Ptr
21.
21
_Reset(static_cast<_Elem *>(_Other._Ptr), _Other._Rep);
22.
22
}
23.
23
24.
24
template<
class
_Ty2>
25.
25
void
_Reset(
const
_Ptr_base<_Ty2>& _Other,
const
_Const_tag&)
26.
26
{
// release resource and take ownership of _Other._Ptr
27.
27
_Reset(const_cast<_Elem *>(_Other._Ptr), _Other._Rep);
28.
28
}
29.
29
30.
30
template<
class
_Ty2>
31.
31
void
_Reset(
const
_Ptr_base<_Ty2>& _Other,
const
_Dynamic_tag&)
32.
32
{
// release resource and take ownership of _Other._Ptr
33.
33
_Elem *_Ptr = dynamic_cast<_Elem *>(_Other._Ptr);
34.
34
if
(_Ptr)
35.
35
_Reset(_Ptr, _Other._Rep);
36.
36
else
37.
37
_Reset();
38.
38
}
39.
39
40.
40
template<
class
_Ty2>
41.
41
void
_Reset(auto_ptr<_Ty2>&& _Other)
42.
42
{
// release resource and take _Other.get()
43.
43
_Ty2 *_Px = _Other.get();
44.
44
_Reset0(_Px,
new
_Ref_count<_Elem>(_Px));
45.
45
_Other.release();
46.
46
_Enable_shared(_Px, _Rep);
47.
47
}
48.
48
49.
49
#
if
_HAS_CPP0X
50.
50
template<
class
_Ty2>
51.
51
void
_Reset(_Ty *_Ptr,
const
_Ptr_base<_Ty2>& _Other)
52.
52
{
// release resource and alias _Ptr with _Other_rep
53.
53
_Reset(_Ptr, _Other._Rep);
54.
54
}
55.
55
#endif
/* _HAS_CPP0X */
56.
56
57.
57
void
_Reset(_Ty *_Other_ptr, _Ref_count_base *_Other_rep)
58.
58
{
// release resource and take _Other_ptr through _Other_rep
59.
59
if
(_Other_rep)
60.
60
_Other_rep->_Incref();
61.
61
_Reset0(_Other_ptr, _Other_rep);
62.
62
}
63.
63
64.
64
void
_Reset(_Ty *_Other_ptr, _Ref_count_base *_Other_rep, bool _Throw)
65.
65
{
// take _Other_ptr through _Other_rep from weak_ptr if not expired
66.
66
// otherwise, leave in default state if !_Throw,
67.
67
// otherwise throw exception
68.
68
if
(_Other_rep && _Other_rep->_Incref_nz())
69.
69
_Reset0(_Other_ptr, _Other_rep);
70.
70
else
if
(_Throw)
71.
71
_THROW_NCEE(bad_weak_ptr,
0
);
72.
72
}
实际上也就是转发一下到_Reset0函数
------------------------------------------------------------ _Ptr_base的_Resetw函数 ------------------------------------------------------------
除此之外,我们还可以发现_Ptr_base中还有几个类似的函数_Resetw,这几个函数是为了被weak_ptr调用的,在这里我们不详细说,但在下面讨论_Ref_count_base 的时候会被提及。
01.
1
void
_Resetw()
02.
2
{
// release weak reference to resource
03.
3
_Resetw((_Elem *)
0
,
0
);
04.
4
}
05.
5
06.
6
template<
class
_Ty2>
07.
7
void
_Resetw(
const
_Ptr_base<_Ty2>& _Other)
08.
8
{
// release weak reference to resource and take _Other._Ptr
09.
9
_Resetw(_Other._Ptr, _Other._Rep);
10.
10
}
11.
11
12.
12
template<
class
_Ty2>
13.
13
void
_Resetw(
const
_Ty2 *_Other_ptr, _Ref_count_base *_Other_rep)
14.
14
{
// point to _Other_ptr through _Other_rep
15.
15
_Resetw(const_cast<_Ty2*>(_Other_ptr), _Other_rep);
16.
16
}
17.
17
18.
18
template<
class
_Ty2>
19.
19
void
_Resetw(_Ty2 *_Other_ptr, _Ref_count_base *_Other_rep)
20.
20
{
// point to _Other_ptr through _Other_rep
21.
21
if
(_Other_rep)
22.
22
_Other_rep->_Incwref();
23.
23
if
(_Rep !=
0
)
24.
24
_Rep->_Decwref();
25.
25
_Rep = _Other_rep;
26.
26
_Ptr = _Other_ptr;
27.
27
}
--------------------------------------------------------------- _Ref_count_base ---------------------------------------------------------------
_Ref_count_base有两个虚函数,_Ref_count_base的几个子类(带析构器和带构造器)只是override了这两个函数,来产生不同的指针析构行为和自身析构行为。
virtual void _Destroy() = 0;
virtual void _Delete_this() = 0;
因此我们只需要研究_Ref_count_base本身就好。
_Ref_count_base带有两个数据成员(指针数据成员在具体子类里面)
_Atomic_counter_t _Uses;
_Atomic_counter_t _Weaks;
从名字可以猜测出来 _Uses 是shared_ptr的引用计数, _Weaks 是weak_ptr的引用计数
为什么我们需要 _Weaks 呢? 因为在_Uses 引用计数为0(最后一个shared_ptr已经被析构)的时候我们就应该析构掉真正的指针,但问题是这个引用计数对象本身也是一个指针,那么这个引用计数也要在这时候被析构吗?使用过shared_ptr的朋友会知道,shared_ptr 有一个与之紧密相连的类 weak_ptr 实际上由一个shared_ptr 产生的weak_ptr是共享同一个引用计数对象的(这样子weak_ptr就可以知道真正的指针是否被析构掉了)。如果所以 shared_ptr 都被析构掉了同时其引用计数对象,但析构掉了,但有这个 shared_ptr 产生的 weak_ptr 仍然存在那么就可能导致 weak_ptr 访问一个已经被析构的指针。 因此应该是所有的 shared_ptr 与其 产生的weak_ptr 都被析构掉了,其引用计数对象才被析构掉。
我们可以从下面的减少引用计数函数看出来。
PS: #define _MT_DECR _InterlockedIncrement(reinterpret_cast<volatile long *>(&x))
01.
1
void
_Decref()
02.
2
{
// decrement use count
03.
3
if
(_MT_DECR(_Ignored, _Uses) ==
0
)
04.
4
{
// destroy managed resource, decrement weak reference count
05.
5
_Destroy();
06.
6
_Decwref();
07.
7
}
08.
8
}
09.
9
10.
10
void
_Decwref()
11.
11
{
// decrement weak reference count
12.
12
if
(_MT_DECR(_Ignored, _Weaks) ==
0
)
13.
13
_Delete_this();
14.
14
}
与上面相对应的增加引用计数函数
PS: #define _MT_INCR(mtx, x)_InterlockedIncrement(reinterpret_cast<volatile long *>(&x))
01.
1
void
_Incref()
02.
2
{
// increment use count
03.
3
_MT_INCR(_Ignored, _Uses);
04.
4
}
05.
5
06.
6
void
_Incwref()
07.
7
{
// increment weak reference count
08.
8
_MT_INCR(_Ignored, _Weaks);
09.
9
}
再补上 _Ref_count_base 的构造函数
1.
1
_Ref_count_base()
2.
2
{
// construct
3.
3
_Init_atomic_counter(_Uses,
1
);
4.
4
_Init_atomic_counter(_Weaks,
1
);
5.
5
}
我们可以看到 _Ref_count_base 构造函数中对 _Uses 与 _Weaks 初始化引用计数为1,_Uses 为0时析构指针, _Weaks 为0时析构引用计数对象。
比较有趣的是我们可以从 weak_ptr 指针 lock 出一个 shared_ptr 指针的时候,会调用_Ref_count_base 类的函数 _Incref_nz,这个函数检查引用计数对象的引用计数是否为0,非零(未析构真正指针)的时候就可以增加一个引用计数。这里面为了 Lock-Free 调用了函数 _InterlockedCompareExchange。
01.
1
bool _Incref_nz()
02.
2
{
// increment use count if not zero, return true if successful
03.
3
for
(; ; )
04.
4
{
// loop until state is known
05.
5
#
if
defined(_M_IX86) || defined(_M_X64) || defined(_M_CEE_PURE)
06.
6
_Atomic_integral_t _Count =
07.
7
static_cast<
volatile
_Atomic_counter_t&>(_Uses);
08.
8
09.
9
if
(_Count ==
0
)
10.
10
return
(
false
);
11.
11
12.
12
if
(static_cast<_Atomic_integral_t>(_InterlockedCompareExchange(
13.
13
reinterpret_cast<
volatile
long
*>(&_Uses),
14.
14
_Count +
1
, _Count)) == _Count)
15.
15
return
(
true
);
16.
16
#
else
/* defined(_M_IX86) || defined(_M_X64) || defined(_M_CEE_PURE) */
17.
17
_Atomic_integral_t _Count =
18.
18
_Load_atomic_counter_explicit(_Uses, memory_order_relaxed);
19.
19
20.
20
if
(_Count ==
0
)
21.
21
return
(
false
);
22.
22
23.
23
if
(_Compare_increment_atomic_counter_explicit(
24.
24
_Uses, _Count, memory_order_relaxed))
25.
25
return
(
true
);
26.
26
#endif
/* defined(_M_IX86) || defined(_M_X64) || defined(_M_CEE_PURE) */
27.
27
}
28.
28
}
因为 _Ref_count_base 里面的引用计数增加/减少都是Lock-Free的,因此对shared_ptr的引用计数是多线程安全的。
--------------------------------------------------------------- shared_ptr的线程安全---------------------------------------------------------------
多个线程同时对同一个shared_ptr的写操作是不安全的,因为其swap函数
1.
1
void
swap(_Myt& _Other) _NOEXCEPT
2.
2
{
// swap pointers
3.
3
this
->_Swap(_Other);
4.
4
}
调用了一个非线程安全函数_Ptr_base的_Swap
1.
1
void
_Swap(_Ptr_base& _Right)
2.
2
{
// swap pointers
3.
3
_STD swap(_Rep, _Right._Rep);
4.
4
_STD swap(_Ptr, _Right._Ptr);
5.
5
}
但是多个线程同时对共享引用计数的不同shared_ptr的写操作是安全的,因为对于真正的指针,shared_ptr只对其进行简单的读写不修改其指向的对象的内部状态,而且同一时刻只有一个线程对某个shared_ptr真正的指针进行读写,因此线程安全的。对于引用计数对象,虽然修改了其内部状态,但本身这种修改动作是线程安全的。所以我们可以推论多个线程同时对共享引用计数的不同shared_ptr的写操作也是安全的。
boost库对shared_ptr的描述也证明了这一点。
shared_ptr objects offer the same level of thread safety as builtin types.
A shared_ptr instance can be 'read' (accessed using only const operations) simultaneously by multiple threads.
Different shared_ptr instances can be 'written to' (accessed using mutable operations such as operator= or reset) simultaneosly
by multiple threads (even when these instances are copies, and share the same reference count underneath.)
Any other simultaneous accesses result in undefined behavior.
翻译为中文如下:
shared_ptr 对象提供与内建类型一样的线程安全级别。一个 shared_ptr 实例可以同时被多个线程“读”(仅使用不变操作进行访问)。 不同的 shared_ptr 实例可以同时被多个线程“写入”(使用类似 operator= 或 reset 这样的可变操作进行访问)(即使这些实 例是拷贝,而且共享下层的引用计数)。
任何其它的同时访问的结果会导致未定义行为。”
联系客服