-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
399 lines (381 loc) · 236 KB
/
search.xml
File metadata and controls
399 lines (381 loc) · 236 KB
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[scoped_ptr类模版]]></title>
<url>http://deyituo.github.io/2016/06/14/scoped-ptr%E7%B1%BB%E6%A8%A1%E7%89%88/</url>
<content type="html"><![CDATA[<blockquote>
<p>最近在看陈硕的《Linux多线程服务端编程:使用muduo C++网络库》,第一章中重点讲了多线程下指针的处理问题,其中重点是 shared_ptr 与 weak_ptr, 其中还提到在内存泄露和重复释放中使用 scoped_ptr。 上三篇学习了 shared_ptr 的基本用法 ( <a href="/2016/06/09/shared-ptr类模版/">shared_ptr类模版</a> ,<a href="/2016/06/12/shared-ptr类模版-2/">shared_ptr类模板(2)</a>) 和 weak_ptr 的基本用法 ( <a href="/2016/06/11/weak-ptr类模版/">waek_ptr类模版</a> ) ,今天继续学习 scoped_ptr ,以下是对 <a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/scoped_ptr.htm" target="_blank" rel="external">scoped_ptr class template</a> 的部分中文翻译。</p>
</blockquote>
<a id="more"></a>
<h2 id="基本用法"><a href="#基本用法" class="headerlink" title="基本用法"></a>基本用法</h2><h3 id="保证销毁"><a href="#保证销毁" class="headerlink" title="保证销毁"></a>保证销毁</h3><p>scoped_ptr 保存了动态分配对象的指针 (C++ 的 new 操作符)。当 scoped_ptr 被析构或者 reset 的时候,被指向的对象保证被销毁。</p>
<h3 id="不可复制"><a href="#不可复制" class="headerlink" title="不可复制"></a>不可复制</h3><p>scoped_ptr 模版提供了基本的“资源只需要初始化”的机制,没有共享所有权或者传递所有权的语义,只是在当前的范围保留所有权 (<a href="http://www.boost.org/doc/libs/1_61_0/libs/utility/utility.htm#Class_noncopyable" target="_blank" rel="external">noncopyable</a>),因为它不能拷贝,所以对于不应该被复制的指针,比 shared_ptr 或者 std::auto_ptr 要安全。</p>
<h3 id="效率与空间"><a href="#效率与空间" class="headerlink" title="效率与空间"></a>效率与空间</h3><p>因为 scoped_ptr 是简单的,它的操作与内置的指针一样快,占据的空间也不多。</p>
<h3 id="scoped-ptr-与-C-标准库"><a href="#scoped-ptr-与-C-标准库" class="headerlink" title="scoped_ptr 与 C++ 标准库"></a>scoped_ptr 与 C++ 标准库</h3><p>scoped_ptr 不能用在 C++ 标准库容器中,请使用需要需要智能指针来用于容器,请使用 <a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/shared_ptr.htm" target="_blank" rel="external">shared_ptr</a>。</p>
<h3 id="数组指针"><a href="#数组指针" class="headerlink" title="数组指针"></a>数组指针</h3><p>scoped_ptr 不能正确地保存动态分配的数组的指针。<a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/scoped_array.htm" target="_blank" rel="external">scoped_array</a> 提供了这用途。</p>
<h3 id="T-的要求"><a href="#T-的要求" class="headerlink" title="T 的要求"></a>T 的要求</h3><p>scoped_ptr 的模版参数 T 是指向对象的类型,需要满足智能指针的 <a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/smart_ptr.htm#common_requirements" target="_blank" rel="external"><strong>通常要求</strong></a>:</p>
<blockquote>
<p>这些智能指针类模版由一个模版参数 T , 指定了被智能指针指向的对象的类型。如果 T 类型对象的 <strong>析构函数</strong> 或者 <strong> operator delete</strong> 抛出异常,那么智能指针模版的行为无定义。<br>在智能指针声明的时候,T 可能是不完整类型。除非特别说明,当智能指针实例化的时候,需要 T 是完整类型。实现需要检查所有违反该需求的情况,包括不完整类型的销毁操作。->查看 [checked delete] 函数模版的描述。<br>注意 shared_ptr 没有这个限制,因为它的大多数成员函数不需要 T 是完整类型。<br>注意析构时,scoped_ptr 需要 T 是完整类型,而 shared_ptr 不需要。</p>
</blockquote>
<h2 id="Synopsis"><a href="#Synopsis" class="headerlink" title="Synopsis"></a>Synopsis</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">namespace</span> boost {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T> <span class="keyword">class</span> scoped_ptr : noncopyable {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line"> <span class="keyword">typedef</span> T element_type;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">explicit</span> <span class="title">scoped_ptr</span><span class="params">(T * p = <span class="number">0</span>)</span></span>; <span class="comment">// never throws</span></span><br><span class="line"> ~scoped_ptr(); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">reset</span><span class="params">(T * p = <span class="number">0</span>)</span></span>; <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> T & <span class="keyword">operator</span>*() <span class="keyword">const</span>; <span class="comment">// never throws</span></span><br><span class="line"> T * <span class="keyword">operator</span>->() <span class="keyword">const</span>; <span class="comment">// never throws</span></span><br><span class="line"> <span class="function">T * <span class="title">get</span><span class="params">()</span> <span class="keyword">const</span></span>; <span class="comment">// never throws</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">operator</span> unspecified-<span class="keyword">bool</span>-type() <span class="keyword">const</span>; <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">swap</span><span class="params">(scoped_ptr & b)</span></span>; <span class="comment">// never throws</span></span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T> <span class="function"><span class="keyword">void</span> <span class="title">swap</span><span class="params">(scoped_ptr<T> & a, scoped_ptr<T> & b)</span></span>; <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="Members"><a href="#Members" class="headerlink" title="Members"></a>Members</h2><h3 id="element-type"><a href="#element-type" class="headerlink" title="element_type"></a>element_type</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> T element_type;</span><br></pre></td></tr></table></figure>
<p>存储指针的类型。</p>
<h3 id="构造函数"><a href="#构造函数" class="headerlink" title="构造函数"></a>构造函数</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">explicit</span> <span class="title">scoped_ptr</span><span class="params">(T * p = <span class="number">0</span>)</span></span>; <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<p>构建一个 scopeda_ptr, 存储了 p 的拷贝 (p 必须由 new 表达式分配或者为 0)。T 不需要是完整类型,看智能指针的 <a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/smart_ptr.htm#common_requirements" target="_blank" rel="external"><strong>通常要求</strong></a>。</p>
<h3 id="析构函数"><a href="#析构函数" class="headerlink" title="析构函数"></a>析构函数</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~scoped_ptr(); <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<p>析构保存的指针指向的对象,和 delete this->get() 效果一样。</p>
<p>不抛出异常使用了 delete 对象时不抛出异常的要求。看智能指针的 <a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/smart_ptr.htm#common_requirements" target="_blank" rel="external"><strong>通常要求</strong></a>。</p>
<h3 id="reset"><a href="#reset" class="headerlink" title="reset"></a>reset</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">reset</span><span class="params">(T * p = <span class="number">0</span>)</span></span>; <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<p>析构保存的指针指向的对象,再保存 p 的拷贝 (p 必须由 new 表达式分配或者为 0)。不抛出异常使用了 delete 对象时不抛出异常的要求。看智能指针的 <a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/smart_ptr.htm#common_requirements" target="_blank" rel="external"><strong>通常要求</strong></a>。</p>
<h3 id="indirection"><a href="#indirection" class="headerlink" title="indirection"></a>indirection</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">T & <span class="keyword">operator</span>*() <span class="keyword">const</span>; <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<p>返回保存的指针指向对象的引用,如果保存的指针为 0,那么行为将是未定义的。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">T * <span class="keyword">operator</span>->() <span class="keyword">const</span>; <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<p>返回保存的指针,如果保存的指针为 0,那么行为将是未定义的。</p>
<h3 id="get"><a href="#get" class="headerlink" title="get"></a>get</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">T * <span class="title">get</span><span class="params">()</span> <span class="keyword">const</span></span>; <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<p>返回保存的指针,<strong>T 必须为完整类型</strong>。看智能指针的 <a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/smart_ptr.htm#common_requirements" target="_blank" rel="external"><strong>通常要求</strong></a>。</p>
<h3 id="conversions"><a href="#conversions" class="headerlink" title="conversions"></a>conversions</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">operator</span> unspecified-<span class="keyword">bool</span>-type () <span class="keyword">const</span>; <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<p>返回未指定的值,当用于 boolean 上下文时,等同于 get() != 0。</p>
<h3 id="swap"><a href="#swap" class="headerlink" title="swap"></a>swap</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">swap</span><span class="params">(scoped_ptr & b)</span></span>; <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<p>交换两个智能指针的内容,T 不需要为完整类型。看智能指针的 <a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/smart_ptr.htm#common_requirements" target="_blank" rel="external"><strong>通常要求</strong></a>。</p>
<h2 id="Free-Functions"><a href="#Free-Functions" class="headerlink" title="Free Functions"></a>Free Functions</h2><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">template<<span class="class"><span class="keyword">class</span> <span class="title">T</span>> <span class="title">void</span> <span class="title">swap</span>(<span class="title">scoped_ptr</span><T> & <span class="title">a</span>, <span class="title">scoped_ptr</span><T> & <span class="title">b</span>);</span> /<span class="regexp">/ never throws</span></span><br></pre></td></tr></table></figure>
<p>等同于 a.swap(b)。符合 std::swap 接口,提供了泛型编程的支持。</p>
<h2 id="Example"><a href="#Example" class="headerlink" title="Example"></a>Example</h2><p>下面这个例子展示了 scoped_ptr 的使用:<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// scoped_ptr_example1.cpp</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><boost/scoped_ptr.hpp></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> Shoe { ~Shoe() { <span class="built_in">std</span>::<span class="built_in">cout</span> << <span class="string">"Buckle my shoe\n"</span>; } };</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> MyClass {</span><br><span class="line"> boost::scoped_ptr<<span class="keyword">int</span>> ptr;</span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line"> MyClass() : ptr(<span class="keyword">new</span> <span class="keyword">int</span>) { *ptr = <span class="number">0</span>; }</span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">add_one</span><span class="params">()</span> </span>{ <span class="keyword">return</span> ++*ptr; }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span><br><span class="line"></span>{</span><br><span class="line"> boost::scoped_ptr<Shoe> x(<span class="keyword">new</span> Shoe);</span><br><span class="line"> MyClass my_instance;</span><br><span class="line"> <span class="built_in">std</span>::<span class="built_in">cout</span> << my_instance.add_one() << <span class="string">'\n'</span>;</span><br><span class="line"> <span class="built_in">std</span>::<span class="built_in">cout</span> << my_instance.add_one() << <span class="string">'\n'</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>编译运行<br><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">g++ -g scoped_ptr_example1<span class="selector-class">.cpp</span> -o scoped_ptr_example1</span><br><span class="line">./scoped_ptr_example1</span><br><span class="line"></span><br><span class="line"><span class="number">1</span></span><br><span class="line"><span class="number">2</span></span><br><span class="line">Buckle my shoe</span><br></pre></td></tr></table></figure></p>
<h2 id="Rationale"><a href="#Rationale" class="headerlink" title="Rationale"></a>Rationale</h2><p>使用 scoped_ptr 的主要原因是它 比 auto_ptr 更加直观,更加便于维护。</p>
<h2 id="Handle-Body-Idiom"><a href="#Handle-Body-Idiom" class="headerlink" title="Handle/Body Idiom"></a>Handle/Body Idiom</h2><p>scoped_ptr 的一个通常用法是实现 handle/body (也称为 pimpl) idiom,它能避免再头文件中暴露具体实现。<br><a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/example/scoped_ptr_example_test.cpp" target="_blank" rel="external">scoped_ptr_example_test.cpp</a> 例子包含了一个使用 scoped_ptr<> 来隐藏实现的头文件 <a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/example/scoped_ptr_example.hpp" target="_blank" rel="external">scoped_ptr_example.hpp</a> 和 包含了需要完整类型的成员函数实例化 <a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/example/scoped_ptr_example.cpp" target="_blank" rel="external">scoped_ptr_example.cpp</a>。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// scoped_ptr_example.hpp</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Boost scoped_ptr_example header file ------------------------------------//</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Copyright Beman Dawes 2001. Distributed under the Boost</span></span><br><span class="line"><span class="comment">// Software License, Version 1.0. (See accompanying file</span></span><br><span class="line"><span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// See http://www.boost.org/libs/smart_ptr for documentation.</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><boost/utility.hpp></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><boost/scoped_ptr.hpp></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// The point of this example is to prove that even though</span></span><br><span class="line"><span class="comment">// example::implementation is an incomplete type in translation units using</span></span><br><span class="line"><span class="comment">// this header, scoped_ptr< implementation > is still valid because the type</span></span><br><span class="line"><span class="comment">// is complete where it counts - in the inplementation translation unit where</span></span><br><span class="line"><span class="comment">// destruction is actually instantiated.</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> example : <span class="keyword">private</span> boost::noncopyable</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line"> example();</span><br><span class="line"> ~example();</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">do_something</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="keyword">private</span>:</span><br><span class="line"> <span class="keyword">class</span> implementation;</span><br><span class="line"> boost::scoped_ptr< implementation > _imp; <span class="comment">// hide implementation details</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// scoped_ptr_example.cpp</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Boost scoped_ptr_example implementation file -----------------------------//</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Copyright Beman Dawes 2001. Distributed under the Boost</span></span><br><span class="line"><span class="comment">// Software License, Version 1.0. (See accompanying file</span></span><br><span class="line"><span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// See http://www.boost.org/libs/smart_ptr for documentation.</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="string">"scoped_ptr_example.hpp"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> example::implementation</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line"> ~implementation() { <span class="built_in">std</span>::<span class="built_in">cout</span> << <span class="string">"destroying implementation\n"</span>; }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">example::example() : _imp( <span class="keyword">new</span> implementation ) {}</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> example::do_something() { <span class="built_in">std</span>::<span class="built_in">cout</span> << <span class="string">"did something\n"</span>; }</span><br><span class="line"></span><br><span class="line">example::~example() {}</span><br></pre></td></tr></table></figure>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Boost scoped_ptr_example_test main program -------------------------------//</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Copyright Beman Dawes 2001. Distributed under the Boost</span></span><br><span class="line"><span class="comment">// Software License, Version 1.0. (See accompanying file</span></span><br><span class="line"><span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// See http://www.boost.org/libs/smart_ptr for documentation.</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="string">"scoped_ptr_example.hpp"</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span><br><span class="line"></span>{</span><br><span class="line"> example my_example;</span><br><span class="line"> my_example.do_something();</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>编译运行<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">g++ -g scoped_ptr_example.cpp scoped_ptr_example_test.cpp -o scoped_ptr_example_test</span><br><span class="line">./scoped_ptr_example_test</span><br><span class="line"></span><br><span class="line">did something</span><br><span class="line">destroying implementation</span><br></pre></td></tr></table></figure></p>
]]></content>
</entry>
<entry>
<title><![CDATA[shared_ptr类模版(2)]]></title>
<url>http://deyituo.github.io/2016/06/12/shared-ptr%E7%B1%BB%E6%A8%A1%E7%89%88-2/</url>
<content type="html"><![CDATA[<blockquote>
<p>最近在看陈硕的《Linux多线程服务端编程:使用muduo C++网络库》,第一章中重点讲了多线程下指针的处理问题,其中重点是 shared_ptr 与 weak_ptr, 上两篇学习了 shared_ptr 的基本用法 ( <a href="/2016/06/09/shared-ptr类模版/">shared_ptr类模版</a> ) 和 weak_ptr 的基本用法 ( <a href="/2016/06/11/weak-ptr类模版/">waek_ptr类模版</a> ) ,今天继续学习 shared_ptr ,以下是对 <a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/sp_techniques.html" target="_blank" rel="external">Smart Pointer Programming Techniques</a> 的部分中文翻译。</p>
</blockquote>
<a id="more"></a>
<h2 id="Using-incomplete-classes-for-implementation-hiding"><a href="#Using-incomplete-classes-for-implementation-hiding" class="headerlink" title="Using incomplete classes for implementation hiding"></a>Using incomplete classes for implementation hiding</h2><p>分离接口与实现的一个有效方式是使用不完整类型类的指针。<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> FILE;</span><br><span class="line"></span><br><span class="line"><span class="function">FILE * <span class="title">fopen</span><span class="params">(<span class="keyword">char</span> <span class="keyword">const</span> * name, <span class="keyword">char</span> <span class="keyword">const</span> * mode)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">fread</span><span class="params">(FILE * f, <span class="keyword">void</span> * data, <span class="keyword">size_t</span> size)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">fclose</span><span class="params">(FILE * f)</span></span>;</span><br></pre></td></tr></table></figure></p>
<p>可以使用 shared_ptr 来表达上面的接口,使得不需要手动调用 fclose。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> FILE;</span><br><span class="line"></span><br><span class="line"><span class="built_in">shared_ptr</span><FILE> fopen(<span class="keyword">char</span> <span class="keyword">const</span> * name, <span class="keyword">char</span> <span class="keyword">const</span> * mode);</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">fread</span><span class="params">(<span class="built_in">shared_ptr</span><FILE> f, <span class="keyword">void</span> * data, <span class="keyword">size_t</span> size)</span></span>;</span><br></pre></td></tr></table></figure>
<p>这种方式是利用了 shared_ptr 能够自动调用 deleter 的机制来去除了 fclose 的显示调用,实际上,当 X 是不完整类型时,shared_ptr< X > 能够被拷贝和销毁。</p>
<h2 id="The-“Pimpl”-idiom"><a href="#The-“Pimpl”-idiom" class="headerlink" title="The “Pimpl” idiom"></a>The “Pimpl” idiom</h2><p>不完整类的一个 C++ 变种是 “Pimpl” idiom,不完整类没有暴露于用户,shared_ptr 能够用来实现一个 “Pimpl”:<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// file.hpp:</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> file</span><br><span class="line">{</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"></span><br><span class="line"> <span class="keyword">class</span> impl;</span><br><span class="line"> <span class="built_in">shared_ptr</span><impl> pimpl_;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"></span><br><span class="line"> file(<span class="keyword">char</span> <span class="keyword">const</span> * name, <span class="keyword">char</span> <span class="keyword">const</span> * mode);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// compiler generated members are fine and useful</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">read</span><span class="params">(<span class="keyword">void</span> * data, <span class="keyword">size_t</span> size)</span></span>;</span><br><span class="line">};</span><br></pre></td></tr></table></figure></p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// file.cpp:</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="string">"file.hpp"</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> file::impl</span><br><span class="line">{</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"></span><br><span class="line"> impl(impl <span class="keyword">const</span> &);</span><br><span class="line"> impl & <span class="keyword">operator</span>=(impl <span class="keyword">const</span> &);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// private data</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"></span><br><span class="line"> impl(<span class="keyword">char</span> <span class="keyword">const</span> * name, <span class="keyword">char</span> <span class="keyword">const</span> * mode) { ... }</span><br><span class="line"> ~impl() { ... }</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">read</span><span class="params">(<span class="keyword">void</span> * data, <span class="keyword">size_t</span> size)</span> </span>{ ... }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">file::file(<span class="keyword">char</span> <span class="keyword">const</span> * name, <span class="keyword">char</span> <span class="keyword">const</span> * mode): pimpl_(<span class="keyword">new</span> impl(name, mode))</span><br><span class="line">{</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> file::read(<span class="keyword">void</span> * data, <span class="keyword">size_t</span> size)</span><br><span class="line">{</span><br><span class="line"> pimpl_->read(data, size);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>这里的关键点是编译器产生的复制拷贝函数,赋值函数,析构函数都有其意义(代码中file没有定义),因此,file 是可以拷贝复制和赋值的,使得它能够用在标准容器里。</p>
<h2 id="Using-abstract-classes-for-implementation-hiding"><a href="#Using-abstract-classes-for-implementation-hiding" class="headerlink" title="Using abstract classes for implementation hiding"></a>Using abstract classes for implementation hiding</h2><p>另外一个在 C++ 中分离接口与实现的方式是使用 <strong>虚基类</strong> 和 <strong>工厂函数</strong>,虚类有时候被称为接口,这种模式被称为基于接口编程 (“interface-based programming” ),这时,shared_ptr 可以作为工厂函数的返回类型。<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// X.hpp:</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> X</span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">f</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line"> <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">g</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line"></span><br><span class="line"> ~X() {}</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="built_in">shared_ptr</span><X> createX();</span><br></pre></td></tr></table></figure></p>
<p>留意 X_impl 放在了 cpp 中声明和定义。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//X.cpp:</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> X_impl: <span class="keyword">public</span> X</span><br><span class="line">{</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"></span><br><span class="line"> X_impl(X_impl <span class="keyword">const</span> &);</span><br><span class="line"> X_impl & <span class="keyword">operator</span>=(X_impl <span class="keyword">const</span> &);</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">f</span><span class="params">()</span></span><br><span class="line"> </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">g</span><span class="params">()</span></span><br><span class="line"> </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="built_in">shared_ptr</span><X> createX()</span><br><span class="line">{</span><br><span class="line"> <span class="built_in">shared_ptr</span><X> px(<span class="keyword">new</span> X_impl);</span><br><span class="line"> <span class="keyword">return</span> px;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>shared_ptr 的一个关键属性是分配内存,构造函数,释放内存,析构函数的细节是在工厂函数的构造函数里面开始的。留意例子中的被保护的非虚析构函数(虚析构函数可以确保程序正确调用指针对象的析构函数,如果没有 virtual 关键字,则由指针的类型决定析构函数),客户代码不能够(也不需要)删除指向 X 的指针;createX 返回的 shared_ptr< X > 能够正确地调用 ~X_impl。</p>
<h2 id="Preventing-delete-px-get"><a href="#Preventing-delete-px-get" class="headerlink" title="Preventing delete px.get()"></a>Preventing delete px.get()</h2><p>阻止客户代码试图删除一个被 shared_ptr 管理的指针是经常需要的,前面的技术中展示了其中一个办法,使用 protected 的析构函数,另外一个方法是使用私有的 deleter:<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> X</span><br><span class="line">{</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"></span><br><span class="line"> ~X();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">class</span> deleter;</span><br><span class="line"> <span class="keyword">friend</span> <span class="keyword">class</span> deleter;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">class</span> deleter</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">operator</span><span class="params">()</span><span class="params">(X * p)</span> </span>{ <span class="keyword">delete</span> p; }</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"></span><br><span class="line"> <span class="keyword">static</span> <span class="built_in">shared_ptr</span><X> create()</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">shared_ptr</span><X> px(<span class="keyword">new</span> X, X::deleter());</span><br><span class="line"> <span class="keyword">return</span> px;</span><br><span class="line"> }</span><br><span class="line">};</span><br></pre></td></tr></table></figure></p>
<h2 id="Using-a-shared-ptr-to-hold-a-pointer-to-an-array"><a href="#Using-a-shared-ptr-to-hold-a-pointer-to-an-array" class="headerlink" title="Using a shared_ptr to hold a pointer to an array"></a>Using a shared_ptr to hold a pointer to an array</h2><p>shared_ptr 能够用来保存 new[] 操作出来的数组的指针:<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">shared_ptr</span><X> px(<span class="keyword">new</span> X[<span class="number">1</span>], checked_array_deleter<X>());</span><br></pre></td></tr></table></figure></p>
<p>注意,如果有得选择,<a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/shared_array.htm" target="_blank" rel="external">shared_array</a> 更经常适合这个任务,它有一个专门为数组设计的接口,不需要 operator* 与 operator->,并且不需要指针的转化。(?)</p>
<h2 id="Encapsulating-allocation-details-wrapping-factory-functions"><a href="#Encapsulating-allocation-details-wrapping-factory-functions" class="headerlink" title="Encapsulating allocation details, wrapping factory functions"></a>Encapsulating allocation details, wrapping factory functions</h2><p>shared_ptr 能够用来创建 C++ 的 wrappers 来适应现有 C 风格的库接口(库接口中工厂函数返回的指针),从而封装内存分配的细节。考虑下面这个接口,CreateX 可能从它的私有堆里分配内存给 X, ~X 可能无法访问,或者 X 可能不是完整的:<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">X * <span class="title">CreateX</span><span class="params">()</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">DestroyX</span><span class="params">(X *)</span></span>;</span><br><span class="line">``` </span><br><span class="line">销毁 CreateX 返回的指针的唯一方法是调用 DestroyX 函数。</span><br><span class="line"><span class="built_in">shared_ptr</span> 的 wrapper 可能如下:</span><br><span class="line">```C++</span><br><span class="line"><span class="built_in">shared_ptr</span><X> createX()</span><br><span class="line">{</span><br><span class="line"> <span class="built_in">shared_ptr</span><X> px(CreateX(), DestroyX);</span><br><span class="line"> <span class="keyword">return</span> px;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>客户端代码调用 createX 不需要知道对象是如何被分配内存的,析构也是自动的。</p>
<h2 id="Using-a-shared-ptr-to-hold-a-pointer-to-a-statically-allocated-object"><a href="#Using-a-shared-ptr-to-hold-a-pointer-to-a-statically-allocated-object" class="headerlink" title="Using a shared_ptr to hold a pointer to a statically allocated object"></a>Using a shared_ptr to hold a pointer to a statically allocated object</h2><p>有时给一个已经存在的对象创建一个 shared_ptr ,因此,当没有更多引用剩下时,shared_ptr 不试图去销毁这个对象,如下工厂函数:<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">shared_ptr</span><X> createX();</span><br></pre></td></tr></table></figure></p>
<p>有些时候需要返回静态分配 X 的指针,解决方法是使用自定义的 deleter 不做任何东西:<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> null_deleter</span><br><span class="line">{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">operator</span><span class="params">()</span><span class="params">(<span class="keyword">void</span> <span class="keyword">const</span> *)</span> <span class="keyword">const</span></span><br><span class="line"> </span>{</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> X x;</span><br><span class="line"></span><br><span class="line"><span class="built_in">shared_ptr</span><X> createX()</span><br><span class="line">{</span><br><span class="line"> <span class="built_in">shared_ptr</span><X> px(&x, null_deleter());</span><br><span class="line"> <span class="keyword">return</span> px;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
]]></content>
</entry>
<entry>
<title><![CDATA[weak_ptr类模版]]></title>
<url>http://deyituo.github.io/2016/06/11/weak-ptr%E7%B1%BB%E6%A8%A1%E7%89%88/</url>
<content type="html"><![CDATA[<blockquote>
<p>最近在看陈硕的《Linux多线程服务端编程:使用muduo C++网络库》,第一章中重点讲了多线程下指针的处理问题,其中重点是 shared_ptr 与 weak_ptr, 上一篇博客学习了 shared_ptr 的基本用法 ( <a href="/2016/06/09/shared-ptr类模版/">shared_ptr类模版</a> ),今天继续学习 weak_ptr ,以下是对 <a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/weak_ptr.htm" target="_blank" rel="external">boost::weak_ptr</a> 的中文翻译。</p>
</blockquote>
<a id="more"></a>
<h2 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h2><h3 id="weak-ptr-转化到-shared-ptr"><a href="#weak-ptr-转化到-shared-ptr" class="headerlink" title="weak_ptr 转化到 shared_ptr"></a>weak_ptr 转化到 shared_ptr</h3><p>weak_ptr 类模版存储了被 shared_ptr 管理的对象的“弱引用”,weak_ptr 能通过使用 <a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/shared_ptr.htm#constructors" target="_blank" rel="external">shared_ptr 的构造函数</a> 或者成员函数 转化到 shared_ptr。当最后一个指向对象的 shared_ptr 被销毁,对象会被销毁。weak_ptr 的对象被销毁后,试图从 weak_ptr 获得 shared_ptr 将失败,并且构造函数会抛出一个类型为 boost::bad_weak_ptr 的异常,weak_ptr::lock 将返回一个空的 shared_ptr。(?)</p>
<h3 id="标准库"><a href="#标准库" class="headerlink" title="标准库"></a>标准库</h3><p>每一个 weak_ptr 都能拷贝构造和赋值,因而能用于标准库容器。另外,还有对比操作符,使得 weak_ptr 能用于标准库的关联容器。</p>
<h3 id="操作"><a href="#操作" class="headerlink" title="操作"></a>操作</h3><p>weak_ptr 操作符不抛出异常。</p>
<p>类模版使用 T 作为参数,T 为指向的对象类型。</p>
<p>与 shared_ptr 对比,weak_ptr 提供了非常有限的部分操作,因为在多线程程序里使用它存储的指针式通常是危险的,甚至在单线程中有时也不安全(也就是说,它会引起无定义的行为)。假设 weak_ptr 拥有一个 get 函数能够返回对象指针,如下面错误的代码:<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">shared_ptr</span><<span class="keyword">int</span>> p(<span class="keyword">new</span> <span class="keyword">int</span>(<span class="number">5</span>));</span><br><span class="line">weak_ptr<<span class="keyword">int</span>> q(p);</span><br><span class="line"></span><br><span class="line"><span class="comment">// some time later</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">int</span> * r = q.get())</span><br><span class="line">{</span><br><span class="line"> <span class="comment">// use *r</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>想象如果在 if 后,在 r 被使用前,另外一个线程运行到了语句 p.reset(),那么 r 现在就成了空悬指针。</p>
<blockquote>
<p>空悬指针(dangling pointer)指向已经销毁的对象或已经回收的地址,野指针(wild pointer)指的是 未经初始化的指针(<a href="http://en.wikipedia.org/wiki/Dangling_pointer)。" target="_blank" rel="external">http://en.wikipedia.org/wiki/Dangling_pointer)。</a></p>
</blockquote>
<p>这个问题的解决办法是从 q 创建一个临时的 shared_ptr :<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">shared_ptr</span><<span class="keyword">int</span>> p(<span class="keyword">new</span> <span class="keyword">int</span>(<span class="number">5</span>));</span><br><span class="line">weak_ptr<<span class="keyword">int</span>> q(p);</span><br><span class="line"></span><br><span class="line"><span class="comment">// some time later</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(<span class="built_in">shared_ptr</span><<span class="keyword">int</span>> r = q.lock())</span><br><span class="line">{</span><br><span class="line"> <span class="comment">// use *r</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>那么现在 r 就有了一个 q 指向对象的引用。即使 p.reset()在另外一个线程被执行,这个对象仍然会存活,直到 r 离开了作用范围或者重新被 reset 了,通过获得对象的 shared_ptr,我们能够有效地锁定它防止销毁。 </p>
<h2 id="Synopsis"><a href="#Synopsis" class="headerlink" title="Synopsis"></a>Synopsis</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">namespace</span> boost {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T> <span class="keyword">class</span> weak_ptr {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line"> <span class="keyword">typedef</span> T element_type;</span><br><span class="line"></span><br><span class="line"> weak_ptr();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> weak_ptr(<span class="built_in">shared_ptr</span><Y> <span class="keyword">const</span> & r);</span><br><span class="line"> weak_ptr(weak_ptr <span class="keyword">const</span> & r);</span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> weak_ptr(weak_ptr<Y> <span class="keyword">const</span> & r);</span><br><span class="line"></span><br><span class="line"> ~weak_ptr();</span><br><span class="line"></span><br><span class="line"> weak_ptr & <span class="keyword">operator</span>=(weak_ptr <span class="keyword">const</span> & r);</span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> weak_ptr & <span class="keyword">operator</span>=(weak_ptr<Y> <span class="keyword">const</span> & r);</span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> weak_ptr & <span class="keyword">operator</span>=(<span class="built_in">shared_ptr</span><Y> <span class="keyword">const</span> & r);</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">long</span> <span class="title">use_count</span><span class="params">()</span> <span class="keyword">const</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">bool</span> <span class="title">expired</span><span class="params">()</span> <span class="keyword">const</span></span>;</span><br><span class="line"> <span class="built_in">shared_ptr</span><T> lock() <span class="keyword">const</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">reset</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">swap</span><span class="params">(weak_ptr<T> & b)</span></span>;</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T, <span class="keyword">class</span> U></span><br><span class="line"> <span class="keyword">bool</span> <span class="keyword">operator</span><(weak_ptr<T> <span class="keyword">const</span> & a, weak_ptr<U> <span class="keyword">const</span> & b);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">swap</span><span class="params">(weak_ptr<T> & a, weak_ptr<T> & b)</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="Members"><a href="#Members" class="headerlink" title="Members"></a>Members</h2><h3 id="element-type"><a href="#element-type" class="headerlink" title="element_type"></a>element_type</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> T element_type;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>提供模版参数 T 的类型</p>
</blockquote>
<h3 id="构造函数"><a href="#构造函数" class="headerlink" title="构造函数"></a>构造函数</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">weak_ptr();</span><br></pre></td></tr></table></figure>
<blockquote>
<p>效果:构建一个空的 weak_ptr 。<br>后置条件:use_count() == 0。<br>抛出:无。</p>
</blockquote>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y> weak_ptr(<span class="built_in">shared_ptr</span><Y> <span class="keyword">const</span> & r);</span><br><span class="line">weak_ptr(weak_ptr <span class="keyword">const</span> & r);</span><br><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y> weak_ptr(weak_ptr<Y> <span class="keyword">const</span> & r);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>效果:如果 r 是空的,构造一个空的 weak_ptr;否则,构造一个 weak_ptr 与 r 共享所有权,同时存储一份 r 中的指针的拷贝。<br>后置条件:use_count() == r.use_count()。<br>抛出:无。</p>
</blockquote>
<h3 id="析构函数"><a href="#析构函数" class="headerlink" title="析构函数"></a>析构函数</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~weak_ptr();</span><br></pre></td></tr></table></figure>
<blockquote>
<p>效果:销毁这个 weak_ptr,但是对它保存的指针指向的对象无影响。<br>抛出:无。</p>
</blockquote>
<h3 id="赋值函数"><a href="#赋值函数" class="headerlink" title="赋值函数"></a>赋值函数</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">weak_ptr & <span class="keyword">operator</span>=(weak_ptr <span class="keyword">const</span> & r);</span><br><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y> weak_ptr & <span class="keyword">operator</span>=(weak_ptr<Y> <span class="keyword">const</span> & r);</span><br><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y> weak_ptr & <span class="keyword">operator</span>=(<span class="built_in">shared_ptr</span><Y> <span class="keyword">const</span> & r);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>效果:等同于 weak_ptr(r).swap(*this)。<br>抛出:无。</p>
</blockquote>
<h3 id="use-count"><a href="#use-count" class="headerlink" title="use_count"></a>use_count</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">long</span> <span class="title">use_count</span><span class="params">()</span> <span class="keyword">const</span></span>;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>返回:如果*this为空,0;否则,与 weak_ptr 所共享所有权的 shared_ptr 的数目。<br>抛出:无。<br>注意:use_count() 不是高效的,只是用来调试和测试。</p>
</blockquote>
<h3 id="expired"><a href="#expired" class="headerlink" title="expired"></a>expired</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">expired</span><span class="params">()</span> <span class="keyword">const</span></span>;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>返回:use_count() == 0。<br>抛出:无。<br>注意:expired() 比 use_count() 快。</p>
</blockquote>
<h3 id="lock"><a href="#lock" class="headerlink" title="lock"></a>lock</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">shared_ptr</span><T> lock() <span class="keyword">const</span>;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>返回:expired() ? shared_ptr< T >() : shared_ptr< T >(*this)。</p>
</blockquote>
<h3 id="reset"><a href="#reset" class="headerlink" title="reset"></a>reset</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">reset</span><span class="params">()</span></span>;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>效果:等价于 weak_ptr().swap(*this)。</p>
</blockquote>
<h3 id="swap"><a href="#swap" class="headerlink" title="swap"></a>swap</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">swap</span><span class="params">(weak_ptr & b)</span></span>;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>效果:交换两个智能指针的内容。<br>抛出:无。</p>
</blockquote>
<h2 id="Free-Functions"><a href="#Free-Functions" class="headerlink" title="Free Functions"></a>Free Functions</h2>]]></content>
</entry>
<entry>
<title><![CDATA[shared_ptr类模版]]></title>
<url>http://deyituo.github.io/2016/06/09/shared-ptr%E7%B1%BB%E6%A8%A1%E7%89%88/</url>
<content type="html"><![CDATA[<blockquote>
<p>最近在看陈硕的《Linux多线程服务端编程:使用muduo C++网络库》,第一章中重点讲了多线程下指针的处理问题,其中重点是 shared_ptr 与 weak_ptr, 但书中对这部分的基础介绍比较简略,以前看过智能指针,但一直没有完整学习过,因而学习翻译了官方的文档进行学习。以下是 <a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/shared_ptr.htm" target="_blank" rel="external">boost::shared_ptr</a> 的中文翻译,其中一部分感觉不是很重要的这里暂时没有给出翻译。 </p>
</blockquote>
<a id="more"></a>
<h2 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h2><p>shared_ptr类模版存储了如用 C++ 的 new 表达式动态分配的对象的指针。当最后一个指向该对象的 share_ptr 被销毁或者重置时,该对象被保证一定会被删除。<br>例如:<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">shared_ptr</span>< X > p1( <span class="keyword">new</span> X );</span><br><span class="line"><span class="built_in">shared_ptr</span>< <span class="keyword">void</span> > p2( <span class="keyword">new</span> <span class="keyword">int</span>(<span class="number">5</span>) );</span><br></pre></td></tr></table></figure></p>
<p>销毁时,不论模版的参数为何,shared_ptr 将删除在构造时所传递真实类型的指针。在第二个例子中,尽管 p2 类型是 shared_ptr< void >, 存储了一个类型为void*的指针, 当 p2 被销毁或者被重置,它将对传递到构造函数的 int* 调用delete函数。</p>
<h3 id="基本成员函数"><a href="#基本成员函数" class="headerlink" title="基本成员函数"></a>基本成员函数</h3><p>shared_ptr 拥有拷贝构造函数,Move构造函数,拷贝赋值函数,Move赋值函数,并且能用在标准库的容器里。对比操作符同样也提供,使得 shared_ptr 能用在标准库中的关联容器里。(关联容器?)</p>
<h3 id="循环嵌套问题"><a href="#循环嵌套问题" class="headerlink" title="循环嵌套问题"></a>循环嵌套问题</h3><p>因为使用了引用计数来作为其实现,因此循环嵌套 shared_ptr 的实体将不会被回收。 例如,如果 main() 有一个指向对象 A 的 shared_ptr,而 A 自身又直接或者间接地拥有一个指向 A 的 shared_ptr,那么 A 的引用计数将为 2。销毁 main() 中的 shared_ptr 将使得 A 的引用计数为 1。(使用 <a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/weak_ptr.htm" target="_blank" rel="external">weak_ptr</a> 打破循环?)</p>
<h3 id="void-模版参数"><a href="#void-模版参数" class="headerlink" title="void 模版参数"></a>void 模版参数</h3><p>shared_ptr 使用 T 来表明所指向的对象的类型,它及它的很多成员函数并不需要使用到 T;它被允许是一个不完整的类型,或者 void,需要使用到 T 的成员函数将在下面文档中介绍。</p>
<h3 id="转换"><a href="#转换" class="headerlink" title="转换"></a>转换</h3><p>shared_ptr< T > 能被隐式地转换到 shared_ptr< U >,T* 能被隐式转换到 U*。特别地, shared_ptr< T > 能被隐式转换为 shared_ptr< T const >;当 U 是 T 的基类时, 能被转换到 shared_ptr< U >;转换到 shared_ptr< void >。</p>
<h3 id="std-shared-ptr"><a href="#std-shared-ptr" class="headerlink" title="std::shared_ptr"></a>std::shared_ptr</h3><p>shared_ptr 是 C++11 一部分,为 std::shared_ptr。</p>
<h3 id="数组指针"><a href="#数组指针" class="headerlink" title="数组指针"></a>数组指针</h3><p>从 Boost 1.53 开始,shared_ptr 能够保存指向动态分配数组的指针,模版参数为 T[] 或者 T[N],两者间几乎没什么差别,后者能够检查进行下标的范围。<br>例如:<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">shared_ptr</span>< <span class="keyword">double</span>[ <span class="number">1024</span> ] > p1( <span class="keyword">new</span> <span class="keyword">double</span>[ <span class="number">1024</span> ])</span><br><span class="line"><span class="built_in">shared_ptr</span>< <span class="keyword">double</span>[] > p2( <span class="keyword">new</span> <span class="keyword">double</span>[n] )</span><br></pre></td></tr></table></figure></p>
<h2 id="Best-practices"><a href="#Best-practices" class="headerlink" title="Best practices"></a>Best practices</h2><p>去除内存泄漏的一个简单方法是:总是使用一个智能指针去存储 new 的结果。每个 new 关键字出现的地方应该有如下的形式:<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">shared_ptr</span>< T > p( <span class="keyword">new</span> Y );</span><br></pre></td></tr></table></figure></p>
<p>这里 shared_ptr 可以用其他以外的智能指针代替; T 和 Y 可以是相同的类型,Y 的构造函数也可以作为传递的参数。</p>
<p>如果你仔细观察,你发现这里不需要使用 delete 语句,try/catch 也很少。</p>
<p>避免使用未命名的临时 shared_ptr 节省代码书写,为说明这个问题,考虑下面这个例子:<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">f</span><span class="params">( <span class="built_in">shared_ptr</span>< <span class="keyword">int</span> >, <span class="keyword">int</span>)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">g</span><span class="params">()</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">ok</span><span class="params">()</span></span><br><span class="line"></span>{</span><br><span class="line"> <span class="built_in">shared_ptr</span>< <span class="keyword">int</span> > p( <span class="keyword">new</span> <span class="keyword">int</span>(<span class="number">2</span>) );</span><br><span class="line"> f( p, g() );</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">bad</span><span class="params">()</span></span><br><span class="line"></span>{</span><br><span class="line"> f( <span class="built_in">shared_ptr</span>< <span class="keyword">int</span> >( <span class="keyword">new</span> <span class="keyword">int</span>(<span class="number">2</span>)), g() );</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>ok函数使用了比较好的方式,而 bad 函数使用了临时的 shared_ptr,导致了内存泄漏的可能。因为函数参数的计算没有指定顺序,可能 new int(2) 会首先执行,然后 g(),但如果函数 g 在执行是抛出了异常,那么我们将无法调用 shared_ptr 的构造函数。 链接 Herb Sutter’s treatment (及here) 对这个问题有更多的说明。</p>
<p>上述描述的异常安全问题也能通过使用 make_shared 或者 allocate_shared 工厂函数被排除(定义在 boost/make_shared.hpp)。这些工厂函数通过整合内存加快了程序的效率。</p>
<h2 id="Synopsis"><a href="#Synopsis" class="headerlink" title="Synopsis"></a>Synopsis</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">namespace</span> boost {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">class</span> bad_weak_ptr: <span class="keyword">public</span> <span class="built_in">std</span>::exception;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T> <span class="keyword">class</span> weak_ptr;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T> <span class="keyword">class</span> <span class="built_in">shared_ptr</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line"></span><br><span class="line"> <span class="keyword">typedef</span> see below element_type;</span><br><span class="line"></span><br><span class="line"> <span class="built_in">shared_ptr</span>(); <span class="comment">// never throws</span></span><br><span class="line"> <span class="built_in">shared_ptr</span>(<span class="built_in">std</span>::<span class="keyword">nullptr_t</span>); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="function"><span class="keyword">explicit</span> <span class="title">shared_ptr</span><span class="params">(Y * p)</span></span>;</span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y, <span class="keyword">class</span> D> <span class="built_in">shared_ptr</span>(Y * p, D d);</span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y, <span class="keyword">class</span> D, <span class="keyword">class</span> A> <span class="built_in">shared_ptr</span>(Y * p, D d, A a);</span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> D> <span class="built_in">shared_ptr</span>(<span class="built_in">std</span>::<span class="keyword">nullptr_t</span> p, D d);</span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> D, <span class="keyword">class</span> A> <span class="built_in">shared_ptr</span>(<span class="built_in">std</span>::<span class="keyword">nullptr_t</span> p, D d, A a);</span><br><span class="line"></span><br><span class="line"> ~<span class="built_in">shared_ptr</span>(); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">shared_ptr</span>(<span class="built_in">shared_ptr</span> <span class="keyword">const</span> & r); <span class="comment">// never throws</span></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="built_in">shared_ptr</span>(<span class="built_in">shared_ptr</span><Y> <span class="keyword">const</span> & r); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">shared_ptr</span>(<span class="built_in">shared_ptr</span> && r); <span class="comment">// never throws</span></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="built_in">shared_ptr</span>(<span class="built_in">shared_ptr</span><Y> && r); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="built_in">shared_ptr</span>(<span class="built_in">shared_ptr</span><Y> <span class="keyword">const</span> & r, element_type * p); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="function"><span class="keyword">explicit</span> <span class="title">shared_ptr</span><span class="params">(weak_ptr<Y> <span class="keyword">const</span> & r)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="function"><span class="keyword">explicit</span> <span class="title">shared_ptr</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">auto_ptr</span><Y> & r)</span></span>;</span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="built_in">shared_ptr</span>(<span class="built_in">std</span>::<span class="built_in">auto_ptr</span><Y> && r);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y, <span class="keyword">class</span> D> <span class="built_in">shared_ptr</span>(<span class="built_in">std</span>::<span class="built_in">unique_ptr</span><Y, D> && r);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">shared_ptr</span> & <span class="keyword">operator</span>=(<span class="built_in">shared_ptr</span> <span class="keyword">const</span> & r); <span class="comment">// never throws</span></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="built_in">shared_ptr</span> & <span class="keyword">operator</span>=(<span class="built_in">shared_ptr</span><Y> <span class="keyword">const</span> & r); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">shared_ptr</span> & <span class="keyword">operator</span>=(<span class="built_in">shared_ptr</span> <span class="keyword">const</span> && r); <span class="comment">// never throws</span></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="built_in">shared_ptr</span> & <span class="keyword">operator</span>=(<span class="built_in">shared_ptr</span><Y> <span class="keyword">const</span> && r); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="built_in">shared_ptr</span> & <span class="keyword">operator</span>=(<span class="built_in">std</span>::<span class="built_in">auto_ptr</span><Y> & r);</span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="built_in">shared_ptr</span> & <span class="keyword">operator</span>=(<span class="built_in">std</span>::<span class="built_in">auto_ptr</span><Y> && r);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y, <span class="keyword">class</span> D> <span class="built_in">shared_ptr</span> & <span class="keyword">operator</span>=(<span class="built_in">std</span>::<span class="built_in">unique_ptr</span><Y, D> && r);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">shared_ptr</span> & <span class="keyword">operator</span>=(<span class="built_in">std</span>::<span class="keyword">nullptr_t</span>); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">reset</span><span class="params">()</span></span>; <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="function"><span class="keyword">void</span> <span class="title">reset</span><span class="params">(Y * p)</span></span>;</span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y, <span class="keyword">class</span> D> <span class="function"><span class="keyword">void</span> <span class="title">reset</span><span class="params">(Y * p, D d)</span></span>;</span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y, <span class="keyword">class</span> D, <span class="keyword">class</span> A> <span class="function"><span class="keyword">void</span> <span class="title">reset</span><span class="params">(Y * p, D d, A a)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="function"><span class="keyword">void</span> <span class="title">reset</span><span class="params">(<span class="built_in">shared_ptr</span><Y> <span class="keyword">const</span> & r, element_type * p)</span></span>; <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> T & <span class="keyword">operator</span>*() <span class="keyword">const</span>; <span class="comment">// never throws; only valid when T is not an array type</span></span><br><span class="line"> T * <span class="keyword">operator</span>->() <span class="keyword">const</span>; <span class="comment">// never throws; only valid when T is not an array type</span></span><br><span class="line"></span><br><span class="line"> element_type & <span class="keyword">operator</span>[](<span class="built_in">std</span>::<span class="keyword">ptrdiff_t</span> i) <span class="keyword">const</span>; <span class="comment">// never throws; only valid when T is an array type</span></span><br><span class="line"></span><br><span class="line"> <span class="function">element_type * <span class="title">get</span><span class="params">()</span> <span class="keyword">const</span></span>; <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">bool</span> <span class="title">unique</span><span class="params">()</span> <span class="keyword">const</span></span>; <span class="comment">// never throws</span></span><br><span class="line"> <span class="function"><span class="keyword">long</span> <span class="title">use_count</span><span class="params">()</span> <span class="keyword">const</span></span>; <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">explicit</span> <span class="keyword">operator</span> <span class="title">bool</span><span class="params">()</span> <span class="keyword">const</span></span>; <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">swap</span><span class="params">(<span class="built_in">shared_ptr</span> & b)</span></span>; <span class="comment">// never throws</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="function"><span class="keyword">bool</span> <span class="title">owner_before</span><span class="params">(<span class="built_in">shared_ptr</span><Y> <span class="keyword">const</span> & rhs)</span> <span class="keyword">const</span></span>; <span class="comment">// never throws</span></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="function"><span class="keyword">bool</span> <span class="title">owner_before</span><span class="params">(weak_ptr<Y> <span class="keyword">const</span> & rhs)</span> <span class="keyword">const</span></span>; <span class="comment">// never throws</span></span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T, <span class="keyword">class</span> U></span><br><span class="line"> <span class="keyword">bool</span> <span class="keyword">operator</span>==(<span class="built_in">shared_ptr</span><T> <span class="keyword">const</span> & a, <span class="built_in">shared_ptr</span><U> <span class="keyword">const</span> & b); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T, <span class="keyword">class</span> U></span><br><span class="line"> <span class="keyword">bool</span> <span class="keyword">operator</span>!=(<span class="built_in">shared_ptr</span><T> <span class="keyword">const</span> & a, <span class="built_in">shared_ptr</span><U> <span class="keyword">const</span> & b); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T, <span class="keyword">class</span> U></span><br><span class="line"> <span class="keyword">bool</span> <span class="keyword">operator</span><(<span class="built_in">shared_ptr</span><T> <span class="keyword">const</span> & a, <span class="built_in">shared_ptr</span><U> <span class="keyword">const</span> & b); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T></span><br><span class="line"> <span class="keyword">bool</span> <span class="keyword">operator</span>==(<span class="built_in">shared_ptr</span><T> <span class="keyword">const</span> & p, <span class="built_in">std</span>::<span class="keyword">nullptr_t</span>); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T></span><br><span class="line"> <span class="keyword">bool</span> <span class="keyword">operator</span>==(<span class="built_in">std</span>::<span class="keyword">nullptr_t</span>, <span class="built_in">shared_ptr</span><T> <span class="keyword">const</span> & p); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T></span><br><span class="line"> <span class="keyword">bool</span> <span class="keyword">operator</span>!=(<span class="built_in">shared_ptr</span><T> <span class="keyword">const</span> & p, <span class="built_in">std</span>::<span class="keyword">nullptr_t</span>); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T></span><br><span class="line"> <span class="keyword">bool</span> <span class="keyword">operator</span>!=(<span class="built_in">std</span>::<span class="keyword">nullptr_t</span>, <span class="built_in">shared_ptr</span><T> <span class="keyword">const</span> & p); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T> <span class="function"><span class="keyword">void</span> <span class="title">swap</span><span class="params">(<span class="built_in">shared_ptr</span><T> & a, <span class="built_in">shared_ptr</span><T> & b)</span></span>; <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T> <span class="keyword">typename</span> <span class="built_in">shared_ptr</span><T>::<span class="function">element_type * <span class="title">get_pointer</span><span class="params">(<span class="built_in">shared_ptr</span><T> <span class="keyword">const</span> & p)</span></span>; <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T, <span class="keyword">class</span> U></span><br><span class="line"> <span class="built_in">shared_ptr</span><T> static_pointer_cast(<span class="built_in">shared_ptr</span><U> <span class="keyword">const</span> & r); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T, <span class="keyword">class</span> U></span><br><span class="line"> <span class="built_in">shared_ptr</span><T> const_pointer_cast(<span class="built_in">shared_ptr</span><U> <span class="keyword">const</span> & r); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T, <span class="keyword">class</span> U></span><br><span class="line"> <span class="built_in">shared_ptr</span><T> dynamic_pointer_cast(<span class="built_in">shared_ptr</span><U> <span class="keyword">const</span> & r); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> T, <span class="keyword">class</span> U></span><br><span class="line"> <span class="built_in">shared_ptr</span><T> reinterpet_pointer_cast(<span class="built_in">shared_ptr</span><U> <span class="keyword">const</span> & r); <span class="comment">// never throws</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> E, <span class="keyword">class</span> T, <span class="keyword">class</span> Y></span><br><span class="line"> <span class="built_in">std</span>::basic_ostream<E, T> & <span class="keyword">operator</span><< (<span class="built_in">std</span>::basic_ostream<E, T> & os, <span class="built_in">shared_ptr</span><Y> <span class="keyword">const</span> & p);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span><<span class="keyword">class</span> D, <span class="keyword">class</span> T></span><br><span class="line"> <span class="function">D * <span class="title">get_deleter</span><span class="params">(<span class="built_in">shared_ptr</span><T> <span class="keyword">const</span> & p)</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="Members"><a href="#Members" class="headerlink" title="Members"></a>Members</h2><h3 id="element-type"><a href="#element-type" class="headerlink" title="element_type"></a>element_type</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> ... element_type;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>当 T 不是数组类型时,element_type 是 T;当 T 是 U[] 或者 U[N] 时,element_type 是 U</p>
</blockquote>
<h3 id="默认构造函数"><a href="#默认构造函数" class="headerlink" title="默认构造函数"></a>默认构造函数</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">shared_ptr</span>(); <span class="comment">// never throws</span></span><br><span class="line"><span class="built_in">shared_ptr</span>(<span class="built_in">std</span>::<span class="keyword">nullptr_t</span>); <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>效果:创建一个空的 shared_ptr。<br>后置条件:use_count() == 0 && get() == 0。<br>抛出:无。</p>
</blockquote>
<p>保证 nothrows 是重要的,因为 reset() 通过默认构造函数来指定,这也表明了默认构造函数不能分配内存空间。</p>
<h3 id="指针构造函数"><a href="#指针构造函数" class="headerlink" title="指针构造函数"></a>指针构造函数</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="function"><span class="keyword">explicit</span> <span class="title">shared_ptr</span><span class="params">(Y *p)</span></span>;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>前置条件:Y 必须是完整类型。当 T 是数组类型时,语句 delete[] p;当 T 非数组类型时,delete p 必须可以执行,不能抛出异常。当 T 是 U[N],Y(<em>)[N] 必须可以转化到 T*;当 T 是 U[],Y(</em>)[] 必须可以转化到 T*;否则, Y* 必须可以转化到 T*。<br>效果:当 T 非数组类型时,构造一个拥有指针 p 的shared_ptr。否则,创建一个拥有指针 p 和一个可以调用 delete[] p 的 deleter。<br>后置条件:use_count() == 1 && get() == p。如果 T 非数组类型并且 p 可以转化到 enable_shared_from_this< V >*,p->shared_from_this()返回 *this 的一个拷贝。<br>抛出:当资源不能被满足时,std::bad_alloc 或者自定义的异常。<br>异常安全:如果异常被抛出,T 是数组类型,构造函数调用 delete[] p;T 非数组类型则调用 delete p。<br>注意:p 必须是指向通过 C++ 的 new 表达式来创建的对象的指针,或者为 0。即使 p 为 0, 后置条件中 use_count() 也为 1;delete 作用于值为 0 的指针无害。</p>
</blockquote>
<p>该构造函数是模版函数,是为记忆传进来的指针的真实类型。析构函数将会调用 delete 作用于原始类型的指针,即使当 T 没有一个虚析构函数或者为 void。</p>
<h3 id="带-deleter-的构造函数"><a href="#带-deleter-的构造函数" class="headerlink" title="带 deleter 的构造函数"></a>带 deleter 的构造函数</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y, <span class="keyword">class</span> D> <span class="built_in">shared_ptr</span>(Y * p, D d);</span><br><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y, <span class="keyword">class</span> D, <span class="keyword">class</span> A> <span class="built_in">shared_ptr</span>(Y * p, D d, A a);</span><br><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> D> <span class="built_in">shared_ptr</span>(<span class="built_in">std</span>::<span class="keyword">nullptr_t</span> p, D d);</span><br><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> D, <span class="keyword">class</span> A> <span class="built_in">shared_ptr</span>(<span class="built_in">std</span>::<span class="keyword">nullptr_t</span> p, D d, A a);</span><br></pre></td></tr></table></figure>
<h3 id="拷贝构造函数"><a href="#拷贝构造函数" class="headerlink" title="拷贝构造函数"></a>拷贝构造函数</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">shared_ptr</span>(<span class="built_in">shared_ptr</span> <span class="keyword">const</span> & r); <span class="comment">// never throws</span></span><br><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="built_in">shared_ptr</span>(<span class="built_in">shared_ptr</span><Y> <span class="keyword">const</span> & r); <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>前置条件:Y* 可以转化到 T*。<br>效果:如果 r 是空的,构造一个空的shared_ptr;否则,构造一个分享 r 的指针所有权的shared_ptr。<br>后置条件:get() == r.get() && use_count() == r.use_count()。<br>抛出:无。</p>
</blockquote>
<h3 id="Move-构造函数"><a href="#Move-构造函数" class="headerlink" title="Move 构造函数"></a>Move 构造函数</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">shared_ptr</span>(<span class="built_in">shared_ptr</span> && r); <span class="comment">// never throws</span></span><br><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="built_in">shared_ptr</span>(<span class="built_in">shared_ptr</span><Y> && r); <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>前置条件:Y* 可以转化到 T*。<br>效果:move 构造一个从 r 的 shared_ptr。<br>后置条件:*this 包含了 r 旧的值。r 为空并且 r.get() == 0。<br>抛出:无。</p>
</blockquote>
<h3 id="aliasing-构造函数"><a href="#aliasing-构造函数" class="headerlink" title="aliasing 构造函数"></a>aliasing 构造函数</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="built_in">shared_ptr</span>(<span class="built_in">shared_ptr</span><Y> <span class="keyword">const</span> & r, element_type * p); <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<h3 id="weak-ptr-构造函数"><a href="#weak-ptr-构造函数" class="headerlink" title="weak_ptr 构造函数"></a>weak_ptr 构造函数</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="function"><span class="keyword">explicit</span> <span class="title">shared_ptr</span><span class="params">(weak_ptr<Y> <span class="keyword">const</span> & r)</span></span>;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>前置条件:Y* 可以转化到 T*。<br>效果:构造一个分享 r 所有权的 shared_ptr 并且复制 r 中的指针。<br>后置条件:use_count() == r.use_count()。<br>抛出:当 r.use_count() == 0, bad_weak_ptr。<br>异常安全:如果异常抛出,构造函数将无效果。</p>
</blockquote>
<h3 id="auto-ptr-构造函数"><a href="#auto-ptr-构造函数" class="headerlink" title="auto_ptr 构造函数"></a>auto_ptr 构造函数</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="built_in">shared_ptr</span>(<span class="built_in">std</span>::<span class="built_in">auto_ptr</span><Y> & r);</span><br><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="built_in">shared_ptr</span>(<span class="built_in">std</span>::<span class="built_in">auto_ptr</span><Y> && r);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>前置条件:Y* 可以转化到 T*。<br>效果:构造一个 shared_ptr,存储 r.release() 的拷贝<br>后置条件:use_count() == 1。<br>抛出:当资源不能被满足时,std::bad_alloc 或者自定义的异常。<br>异常安全:如果异常抛出,构造函数将无效果。</p>
</blockquote>
<h3 id="unique-ptr-构造函数"><a href="#unique-ptr-构造函数" class="headerlink" title="unique_ptr 构造函数"></a>unique_ptr 构造函数</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y, <span class="keyword">class</span> D> <span class="built_in">shared_ptr</span>(<span class="built_in">std</span>::<span class="built_in">unique_ptr</span><Y, D> && r);</span><br></pre></td></tr></table></figure>
<h3 id="析构函数"><a href="#析构函数" class="headerlink" title="析构函数"></a>析构函数</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~<span class="built_in">shared_ptr</span>(); <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>效果:<br> 如果 *this 为空,或者与另外一个 shared_ptr 共享所有权 (use_count()>1),那么没有副作用。<br> 否则,如果 *this 拥有一个指针 p 和一个 deleter d,d(p) 被调用。<br> 否则,*this 拥有一个指针 p, delete p 被调用。<br> 抛出: 无。</p>
</blockquote>
<h3 id="赋值"><a href="#赋值" class="headerlink" title="赋值"></a>赋值</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">shared_ptr</span> & <span class="keyword">operator</span>=(<span class="built_in">shared_ptr</span> <span class="keyword">const</span> & r); <span class="comment">// never throws</span></span><br><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="built_in">shared_ptr</span> & <span class="keyword">operator</span>=(<span class="built_in">shared_ptr</span><Y> <span class="keyword">const</span> & r); <span class="comment">// never throws</span></span><br><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="built_in">shared_ptr</span> & <span class="keyword">operator</span>=(<span class="built_in">std</span>::<span class="built_in">auto_ptr</span><Y> & r);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>效果:等同于 shared_ptr(r).swap(*this)。<br>返回:*this。<br>注意:因为临时对象的构造会使得 use_count() 更新</p>
</blockquote>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">shared_ptr</span> & <span class="keyword">operator</span>=(<span class="built_in">shared_ptr</span> && r); <span class="comment">// never throws</span></span><br><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="built_in">shared_ptr</span> & <span class="keyword">operator</span>=(<span class="built_in">shared_ptr</span><Y> && r); <span class="comment">// never throws</span></span><br><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="built_in">shared_ptr</span> & <span class="keyword">operator</span>=(<span class="built_in">std</span>::<span class="built_in">auto_ptr</span><Y> && r);</span><br><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y, <span class="keyword">class</span> D> <span class="built_in">shared_ptr</span> & <span class="keyword">operator</span>=(<span class="built_in">std</span>::<span class="built_in">unique_ptr</span><Y, D> && r</span><br></pre></td></tr></table></figure>
<blockquote>
<p>效果:等同于 shared_ptr( std::move(r) ).swap(*this)。<br>返回:*this。</p>
</blockquote>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">shared_ptr</span> & <span class="keyword">operator</span>=(<span class="built_in">std</span>::<span class="keyword">nullptr_t</span>); <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>效果:等同于 shared_ptr().swap(*this)。<br>返回:*this。</p>
</blockquote>
<h3 id="reset"><a href="#reset" class="headerlink" title="reset"></a>reset</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">reset</span><span class="params">()</span></span>; <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>效果:等同于 shared_ptr().swap(*this)。</p>
</blockquote>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="function"><span class="keyword">void</span> <span class="title">reset</span><span class="params">(Y * p)</span></span>;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>效果:等同于 shared_ptr(p).swap(*this)。</p>
</blockquote>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y, <span class="keyword">class</span> D> <span class="function"><span class="keyword">void</span> <span class="title">reset</span><span class="params">(Y * p, D d)</span></span>;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>效果:等同于 shared_ptr(p,d).swap(*this)。</p>
</blockquote>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y, <span class="keyword">class</span> D, <span class="keyword">class</span> A> <span class="function"><span class="keyword">void</span> <span class="title">reset</span><span class="params">(Y * p, D d, A a)</span></span>;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>效果:等同于 shared_ptr(p,d,s).swap(*this)。</p>
</blockquote>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="keyword">class</span> Y> <span class="function"><span class="keyword">void</span> <span class="title">reset</span><span class="params">(<span class="built_in">shared_ptr</span><Y> <span class="keyword">const</span> & r, element_type * p)</span></span>; <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>效果:等同于 shared_ptr(r,p).swap(*this)。</p>
</blockquote>
<h3 id="indirection"><a href="#indirection" class="headerlink" title="indirection"></a>indirection</h3><h3 id="get"><a href="#get" class="headerlink" title="get"></a>get</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">element_type * <span class="title">get</span><span class="params">()</span> <span class="keyword">const</span></span>; <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>返回:存储的指针。<br>抛出:无。</p>
</blockquote>
<h3 id="unique"><a href="#unique" class="headerlink" title="unique"></a>unique</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">unique</span><span class="params">()</span> <span class="keyword">const</span></span>; <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>返回:use_count() == 1。<br>抛出:无。<br>注意:unique() 比 use_count() 更快。如果使用 unique() 来实现写拷贝,当存储的指针为 0 时不要依赖特定的值。(?)</p>
</blockquote>
<h3 id="use-count"><a href="#use-count" class="headerlink" title="use_count"></a>use_count</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">long</span> <span class="title">use_count</span><span class="params">()</span> <span class="keyword">const</span></span>; <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>返回:共享所有权的 shared_ptr 的数量,若 *this 为空则为 0。<br>抛出:无。<br>注意:use_count() 不是高效的,只是用来调试和测试。</p>
</blockquote>
<h3 id="conversions"><a href="#conversions" class="headerlink" title="conversions"></a>conversions</h3><h3 id="swap"><a href="#swap" class="headerlink" title="swap"></a>swap</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">swap</span><span class="params">(<span class="built_in">shared_ptr</span> & b)</span></span>; <span class="comment">// never throws</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>效果:交换两个智能指针的内容<br>抛出:无。</p>
</blockquote>
<h2 id="Free-Functions"><a href="#Free-Functions" class="headerlink" title="Free Functions"></a>Free Functions</h2><h2 id="Example"><a href="#Example" class="headerlink" title="Example"></a>Example</h2><p><a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/example/shared_ptr_example.cpp" target="_blank" rel="external">shared_ptr_example.cpp</a> 提供了一个完整的例子,该程序包含了 shared_ptr 对象的 std::vector 和 std::set。<br>注意容器生成后,shared_ptr 的 use_count() 为 2.</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">// Boost shared_ptr_example.cpp --------------------------------------------//</span><br><span class="line"></span><br><span class="line">// Copyright Beman Dawes 2001. Distributed under the Boost</span><br><span class="line">// Software License, Version 1.0. (See accompanying file</span><br><span class="line">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">// See http://www.boost.org/libs/smart_ptr for documentation.</span><br><span class="line"></span><br><span class="line">// Revision History</span><br><span class="line">// 21 May 01 Initial complete version (Beman Dawes)</span><br><span class="line"></span><br><span class="line">// The original code for this example appeared in the shared_ptr documentation.</span><br><span class="line">// Ray Gallimore pointed out that foo_set was missing a Compare template</span><br><span class="line">// argument, so would not work as intended. At that point the code was</span><br><span class="line">// turned into an actual .cpp file so it could be compiled and tested.</span><br><span class="line"></span><br><span class="line">#include <vector></span><br><span class="line">#include <set></span><br><span class="line">#include <iostream></span><br><span class="line">#include <algorithm></span><br><span class="line">#include <boost/shared_ptr.hpp></span><br><span class="line"></span><br><span class="line">// The application will produce a series of</span><br><span class="line">// objects of type Foo which later must be</span><br><span class="line">// accessed both by occurrence (std::vector)</span><br><span class="line">// and by ordering relationship (std::set).</span><br><span class="line"></span><br><span class="line">struct Foo</span><br><span class="line">{ </span><br><span class="line"> Foo( int _x ) : x(_x) {}</span><br><span class="line"> ~Foo() { std::cout << "Destructing a Foo with x=" << x << "\n"; }</span><br><span class="line"> int x;</span><br><span class="line"> /* ... */</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">typedef boost::shared_ptr<Foo> FooPtr;</span><br><span class="line"></span><br><span class="line">struct FooPtrOps</span><br><span class="line">{</span><br><span class="line"> bool operator()( const FooPtr & a, const FooPtr & b )</span><br><span class="line"> { return a->x > b->x; }</span><br><span class="line"> void operator()( const FooPtr & a )</span><br><span class="line"> { std::cout << a->x << " " << a.use_count() << "\n"; }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> std::vector<FooPtr> foo_vector;</span><br><span class="line"> std::set<FooPtr,FooPtrOps> foo_set; // NOT multiset!</span><br><span class="line"></span><br><span class="line"> FooPtr foo_ptr( new Foo( 2 ) );</span><br><span class="line"> foo_vector.push_back( foo_ptr );</span><br><span class="line"> foo_set.insert( foo_ptr );</span><br><span class="line"></span><br><span class="line"> foo_ptr.reset( new Foo( 1 ) );</span><br><span class="line"> foo_vector.push_back( foo_ptr );</span><br><span class="line"> foo_set.insert( foo_ptr );</span><br><span class="line"></span><br><span class="line"> foo_ptr.reset( new Foo( 3 ) );</span><br><span class="line"> foo_vector.push_back( foo_ptr );</span><br><span class="line"> foo_set.insert( foo_ptr );</span><br><span class="line"></span><br><span class="line"> foo_ptr.reset ( new Foo( 2 ) );</span><br><span class="line"> foo_vector.push_back( foo_ptr );</span><br><span class="line"> foo_set.insert( foo_ptr );</span><br><span class="line"></span><br><span class="line"> std::cout << "foo_vector:\n";</span><br><span class="line"> std::for_each( foo_vector.begin(), foo_vector.end(), FooPtrOps() );</span><br><span class="line"> </span><br><span class="line"> std::cout << "\nfoo_set:\n"; </span><br><span class="line"> std::for_each( foo_set.begin(), foo_set.end(), FooPtrOps() );</span><br><span class="line"> std::cout << "\n";</span><br><span class="line"></span><br><span class="line"> return 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>编译运行</p>
<figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">g++ -g shared_ptr_example<span class="selector-class">.cpp</span> -o shared_ptr_example</span><br><span class="line">./shared_ptr_example</span><br><span class="line"></span><br><span class="line">foo_vector:</span><br><span class="line"><span class="number">2</span> <span class="number">2</span></span><br><span class="line"><span class="number">1</span> <span class="number">2</span></span><br><span class="line"><span class="number">3</span> <span class="number">2</span></span><br><span class="line"><span class="number">2</span> <span class="number">2</span></span><br><span class="line"></span><br><span class="line">foo_set:</span><br><span class="line"><span class="number">3</span> <span class="number">2</span></span><br><span class="line"><span class="number">2</span> <span class="number">2</span></span><br><span class="line"><span class="number">1</span> <span class="number">2</span></span><br><span class="line"></span><br><span class="line">Destructing <span class="selector-tag">a</span> Foo with x=<span class="number">2</span></span><br><span class="line">Destructing <span class="selector-tag">a</span> Foo with x=<span class="number">3</span></span><br><span class="line">Destructing <span class="selector-tag">a</span> Foo with x=<span class="number">1</span></span><br><span class="line">Destructing <span class="selector-tag">a</span> Foo with x=<span class="number">2</span></span><br></pre></td></tr></table></figure>
<h2 id="Handle-Body-Idiom"><a href="#Handle-Body-Idiom" class="headerlink" title="Handle/Body Idiom"></a>Handle/Body Idiom</h2><p>shared_ptr 的一个常用地方是实现一个 handle/body (pimpl) idiom, 它可以避免头文件中类的具体实现。<br><a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/example/shared_ptr_example2_test.cpp" target="_blank" rel="external">]shared_ptr_example2_test.cpp</a> 例子包含了一个头文件 <a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/example/shared_ptr_example2.hpp" target="_blank" rel="external">shared_ptr_example2.hpp</a>,该头文件利用 shared_ptr 去隐藏了不完整类型的具体实现。 <a href="http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/example/shared_ptr_example2.cpp" target="_blank" rel="external">shared_ptr_example2.cpp</a> 则包含了具体实现。注意这里不需要一个 explicit 的析构函数。与 ~scoped_ptr 不同,~shared_ptr 不需要 T 是完整类型。(?)</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Boost shared_ptr_example2 header file -----------------------------------//</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Copyright Beman Dawes 2001. Distributed under the Boost</span></span><br><span class="line"><span class="comment">// Software License, Version 1.0. (See accompanying file</span></span><br><span class="line"><span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// See http://www.boost.org/libs/smart_ptr for documentation.</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><boost/shared_ptr.hpp></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// This example demonstrates the handle/body idiom (also called pimpl and</span></span><br><span class="line"><span class="comment">// several other names). It separates the interface (in this header file)</span></span><br><span class="line"><span class="comment">// from the implementation (in shared_ptr_example2.cpp).</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Note that even though example::implementation is an incomplete type in</span></span><br><span class="line"><span class="comment">// some translation units using this header, shared_ptr< implementation ></span></span><br><span class="line"><span class="comment">// is still valid because the type is complete where it counts - in the</span></span><br><span class="line"><span class="comment">// shared_ptr_example2.cpp translation unit where functions requiring a</span></span><br><span class="line"><span class="comment">// complete type are actually instantiated.</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> example</span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> example();</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">do_something</span><span class="params">()</span></span>;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="keyword">class</span> implementation;</span><br><span class="line"> boost::<span class="built_in">shared_ptr</span>< implementation > _imp; <span class="comment">// hide implementation details</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Boost shared_ptr_example2 implementation file -----------------------------//</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Copyright Beman Dawes 2001. Distributed under the Boost</span></span><br><span class="line"><span class="comment">// Software License, Version 1.0. (See accompanying file</span></span><br><span class="line"><span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// See http://www.boost.org/libs/smart_ptr for documentation.</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="string">"shared_ptr_example2.hpp"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> example::implementation</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line"> ~implementation() { <span class="built_in">std</span>::<span class="built_in">cout</span> << <span class="string">"destroying implementation\n"</span>; }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">example::example() : _imp( <span class="keyword">new</span> implementation ) {}</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> example::do_something()</span><br><span class="line"> { <span class="built_in">std</span>::<span class="built_in">cout</span> << <span class="string">"use_count() is "</span> << _imp.use_count() << <span class="string">"\n"</span>; }</span><br></pre></td></tr></table></figure>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Boost shared_ptr_example2_test main program ------------------------------//</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Copyright Beman Dawes 2001. Distributed under the Boost</span></span><br><span class="line"><span class="comment">// Software License, Version 1.0. (See accompanying file</span></span><br><span class="line"><span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// See http://www.boost.org/libs/smart_ptr for documentation.</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="string">"shared_ptr_example2.hpp"</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span><br><span class="line"></span>{</span><br><span class="line"> example a;</span><br><span class="line"> a.do_something();</span><br><span class="line"> <span class="function">example <span class="title">b</span><span class="params">(a)</span></span>;</span><br><span class="line"> b.do_something();</span><br><span class="line"> example c;</span><br><span class="line"> c = a;</span><br><span class="line"> c.do_something();</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>编译运行<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">g++ -g shared_ptr_example2.cpp shared_ptr_example2_test.cpp -o shared_ptr_example2_test</span><br><span class="line">./<span class="function">shared_ptr_example2_test</span><br><span class="line"></span><br><span class="line"><span class="title">use_count</span><span class="params">()</span> is 1</span><br><span class="line"><span class="title">use_count</span><span class="params">()</span> is 2</span><br><span class="line">destroying implementation</span><br><span class="line"><span class="title">use_count</span><span class="params">()</span> is 3</span><br><span class="line">destroying implementation</span></span><br></pre></td></tr></table></figure></p>
<p>这里第一个 destroying implementation 的输出是由于 c = a 语句导致 c 中的 _imp 被析构。</p>
<h2 id="Thread-Safety"><a href="#Thread-Safety" class="headerlink" title="Thread Safety"></a>Thread Safety</h2><p>shared_ptr 对象提供了 C++ 内建类型的线程安全级别。 shared_ptr 对象能被多个线程同时读,不同的 shared_ptr 对象能够被多个线程同时写(即使这些对象是共享同一个引用)。</p>
<p>Example:<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">shared_ptr</span><<span class="keyword">int</span>> p(<span class="keyword">new</span> <span class="keyword">int</span>(<span class="number">42</span>));</span><br></pre></td></tr></table></figure></p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//--- Example 1 ---</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// thread A</span></span><br><span class="line"><span class="built_in">shared_ptr</span><<span class="keyword">int</span>> p2(p); <span class="comment">// reads p</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// thread B</span></span><br><span class="line"><span class="built_in">shared_ptr</span><<span class="keyword">int</span>> p3(p); <span class="comment">// OK, multiple reads are safe</span></span><br></pre></td></tr></table></figure>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//--- Example 2 ---</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// thread A</span></span><br><span class="line">p.reset(<span class="keyword">new</span> <span class="keyword">int</span>(<span class="number">1912</span>)); <span class="comment">// writes p</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// thread B</span></span><br><span class="line">p2.reset(); <span class="comment">// OK, writes p2</span></span><br></pre></td></tr></table></figure>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//--- Example 3 ---</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// thread A</span></span><br><span class="line">p = p3; <span class="comment">// reads p3, writes p</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// thread B</span></span><br><span class="line">p3.reset(); <span class="comment">// writes p3; undefined, simultaneous read/write</span></span><br></pre></td></tr></table></figure>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//--- Example 4 ---</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// thread A</span></span><br><span class="line">p3 = p2; <span class="comment">// reads p2, writes p3</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// thread B</span></span><br><span class="line"><span class="comment">// p2 goes out of scope: undefined, the destructor is considered a "write access"</span></span><br></pre></td></tr></table></figure>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//--- Example 5 ---</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// thread A</span></span><br><span class="line">p3.reset(<span class="keyword">new</span> <span class="keyword">int</span>(<span class="number">1</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">// thread B</span></span><br><span class="line">p3.reset(<span class="keyword">new</span> <span class="keyword">int</span>(<span class="number">2</span>)); <span class="comment">// undefined, multiple writes</span></span><br></pre></td></tr></table></figure>
<p>从 Boost release 1.33.0 开始,shared_ptr 在大多平台上使用了通用锁的实现。<br>如果你的程序是单线程的,并且不需要链接使用了 shared_ptr 的库,你可以使用宏定义 #define BOOST_SP_DISABLE_THREADS 来切换到普通非原子的引用计数更新。<br>你能定义宏 BOOST_SP_USE_PTHREADS 来关闭通用锁,切换回使用普通的 pthread_mutex_t 的代码。</p>
]]></content>
</entry>
<entry>
<title><![CDATA[人脸检测算法概述]]></title>
<url>http://deyituo.github.io/2016/06/07/%E4%BA%BA%E8%84%B8%E6%A3%80%E6%B5%8B%E7%AE%97%E6%B3%95%E6%A6%82%E8%BF%B0/</url>
<content type="html"><![CDATA[<blockquote>
<p>做人脸检测已经一段时间了,临近毕业想想工作后估计应该不会有太多时间再来搞这个,下面抽取了毕业论文的第二章对以前看过的论文进行了总结,写成了下面的综述,涵盖到比较多的方法,希望对看到这篇文章的研究者会有所帮助。</p>
</blockquote>
<a id="more"></a>
<p>自 2001 年 Viola 和 Jones <a href="#1">[1]</a> 将级联分类器的概念引入到人脸检测领域, 其后发展起来的人脸检测算法被设计成更好地处理多角度检测, 遮挡, 模糊等问题 <a href="#15">[15]</a><a href="#16">[16]</a>。 这些算法主要有三大类分支, 第一类是基于级联结构及其改进的算法, 如文献 <a href="#6">[6]</a><a href="#17">[17]</a><a href="#18">[18]</a> 中所提到的人脸检测方法在特征表达, 分类器构造, 运行速率, 多角度模板均进行了大量的改进。级联分类使得检测时非人脸区域可以快速排除, 从而获得了高效的运行速率。 这类人脸检测系统已经被广泛地运用于银行, 摄像头监控系统, 移动手机, 网络社区等。第二类是基于弹性不变模型 (DPM) <a href="#8">[8]</a> 的算法, 这类算法的模型包含若干组成部分, 而这些组成部分通过位置关系进行约束得到整体人脸的检测模型, 这类模型对人脸的形变及遮挡具有很好的适应性和很高的灵活性。 文献 <a href="#9">[9]</a>在得到组成部分的同时进行了人脸标定点, 人脸角度的检测。 第三类是基于神经网络的人脸检测算法, 神经网络主要由若干层卷积层, Pooling 层, 全连接层组成, 对图像提取的卷积网络特征对人脸有更高层次的表达性。 文献 <a href="#19">[19]</a> 通过训练多个神经网络模型来提高人脸检测效果。 由于局部最优问题 <a href="#20">[20]</a> 及训练困难, 过去研究者们更多地进行前两类算法的研究。 随着近年来深度卷积网络的成功, 神经网络算法重新被研究者们所重视。</p>
<p>本文首先详细介绍了基于级联分类器和弹性不变模型的人脸检测算法, 以及当前研究中对这些算法进行的改进。 接着, 简单阐述了神经网络及深度学习的历史, 然后详细介绍了基于神经网络的人脸检测算法以及近来的发展。 最后,本文小结了这三类方法的异同。</p>
<h2 id="基于级联分类器的人脸检测算法"><a href="#基于级联分类器的人脸检测算法" class="headerlink" title="基于级联分类器的人脸检测算法"></a>基于级联分类器的人脸检测算法</h2><p>基于级联分类器的人脸检测算法扩展了 Viola 和 Jones <a href="#1">[1]</a> 最初提出的级联结构 (cascade structure), 其核心思想就是, 让负样本通过所有弱分类器 (weak classifiers) 的概率尽可能低,同时保证正样本通过每层由弱分类组成的强分类器(strong classifier)的最低概率, 达到高检测率低错检率的目的。 在图 2-1 中, 以决策树 (CART) 作为弱分类器为例, 图2-1(a)表示输入的图像, 图2-1(b-g)绿色矩形表示经过若干层后剩下的候选目标区域, 可以看出, 经过 $ 20 $ 层后剩下的候选目标区域集中覆盖在人脸所在的区域,这些区域然后继续被送到后续的分类器。 图2-1(h)表示经过所有层后最终的人脸检测结果, 可以观察到人脸区域可以顺利通过这些弱分类器, 而负样本则被基本过滤了。 </p>
<center><img src="/2016/06/07/人脸检测算法概述/1.png" alt="图2-1 在lena图上使用NPDFace人脸检测器 [[21]](#21) 进行人脸检测。 绿色矩形为经过不同层数所剩下的候选人脸区域 "> 图2-1 在lena图上使用NPDFace人脸检测器 <a href="#21">[21]</a> 进行人脸检测。 绿色矩形为经过不同层数所剩下的候选人脸区域<br><br></center>
<p>Viola 和 Jones 成功将 AdaBoost 机器学习方法 <a href="#22">[22]</a> 引入到人脸检测中, 在文献 <a href="#1">[1]</a><a href="#2">[2]</a> 中采用 Haar 特征进行人脸特征表达, 特征表达简单, 如图 2-2(a)。 提出的积分图概念, 进一步加快了特征提取效率, 然后通过 $ 20 $ 层 AdaBoost 分类器快速过滤掉非人脸区域。 经典的级联 AdaBoost 算法采用单层决策树(stump)作为弱分类器。 训练时, 弱分类器的加权错误为:</p>
<p>$$ \epsilon_i = min \sum_j w_j|h(x_i)-y_i| $$</p>
<p>其中, $ \epsilon_i $ 为第个弱分类器的分类错误, $ w_j $ 为训练样本的权重,$ y_i \in [1,0] $ 表示样本为人脸与非人脸, $ h(x_i) $ 为当前弱分类器对样本 $ x_i $ 的输出得分。 每次训练得到一个弱分类器都会对训练样本的权重重新进行调整, 降低分类正确的样本的权重, 分类错误的样本则与之相反, 从而使得后续的弱分类器针对分类错误的样本。</p>
<p>检测时, 窗口 $ x $ 经过由若干个弱分类器组成的 AdaBoost 强分类器输出为:</p>
<p>$$ C(x) = \begin{cases} 1, \sum_{i}^{T} \alpha_i h_i(x) \gt \eta \\ 0, otherwise \end{cases} , 其中 \alpha_i = log\frac{1-\epsilon_i}{\epsilon_i} $$</p>
<p>其中 $ \eta $ 为保证负样本通过该强分类器概率至多为 $ p_f $, 正样本通过概率至少为的阈值 $ p_t $(如 $ p_f = 0.5, p_t = 0.95 $), 经过 $ 20 $ 层后, 正、负样本通过所有层的概率分别为 $ 0.95^{20} > 0.9, 0.5^{20}< 10^{-6} $。</p>
<center><img src="/2016/06/07/人脸检测算法概述/2.png" alt=" Haar 特征示例 ">(a)Haar 特征示例。灰色矩形内像素和减去白色矩形内像素和为 Haar 特征计算方式,文献 <a href="#1">[1]</a><a href="#2">[2]</a> 采用灰度图进行计算<br><img src="/2016/06/07/人脸检测算法概述/3.png" alt=" 多通道特征 ">(b)多通道特征,从左到右,从上到下依次为LUV彩色通道,梯度响应图、在六个方向上的梯度响应图<br>图2-2 人脸特征<br><br></center>
<p>级联 Adaboost 人脸检测算法以其简单的特征, 高效的实时性而广受欢迎。 但其对人脸进行描述的 Haar 特征对人脸的角度、光照变化、模糊、表情变化等复杂情况适应性较差。 文献 <a href="#4">[4]</a><a href="#5">[5]</a> 进一步扩展了 Haar 特征以适应更多不同的人脸模式。 针对 Haar 特征表达性差的问题, 文献 <a href="#18">[18]</a><a href="#223">[23]</a> 提出了基于更强表达性的SURF <a href="#25">[25]</a> 特征的人脸特征,使用 CPU 并行处理技术及积分图加速特征计算。 人脸特征中纹理特征是一种比较重要的特征, 文献 <a href="#26">[26]</a> 指出纹理分布比纹理强度更有利于分类, 改进了纹理特征 LBP <a href="#27">[27]</a> 来进行人脸表达。 人脸检测算法大多数从灰度图特征提取, 彩色通道由于特征提取困难而被忽视, 而人脸轮廓特征表达能力强, 文献 <a href="#28">[28]</a> 创造性地引入了文献 <a href="#29">[29]</a> 中针对行人检测而提出的基于 LUV 颜色通道及 HOG 特征 <a href="#30">[30]</a> 的多通道特征到人脸检测领域, 运用积分图加速特征计算, 如图 2-2(b)所示。 文献 <a href="#17">[17]</a> 则从文献 <a href="#31">[31]</a> 得到灵感,去除了文献 <a href="#28">[28]</a> 积分图的操作, 在特征选择时直接从多通道特征图中选取, 进一步简化了特征提取过程, 并取得不错的效果。</p>
<p>除了对特征的改进, 级联结构同样也成为研究者们关注的重点。 文献 <a href="#5">[5]</a> 指出 Gentle Adaboost 比原来的 Discrete Adaboost 算法分类效果更好, 深层的决策树需要更少的级联层数。 训练时正样本要尽可能地可以通过弱分类器, 因此弱分类器对损失函数的影响比负样本远远要大, 文献 <a href="#32">[32]</a> 通过降低弱分类器对正样本的输出得分, 从而使得后续的弱分类器更好地针对正样本进行训练。 在文献 <a href="#3">[3]</a> 中将每层强分类器得分改进为当前层强分类器与前面强分类器的累积和, 并将对分类效果无影响的已训练的弱分类器进行了移除, 鲁棒性更强。 文献 <a href="#24">[24]</a> 进一步将强分类器简化为弱分类器, 经过一个弱分类器则进行一次判断, 每个弱分类器的输出为当前弱分类器与之前弱分类器的累加。 单个决策树区分能力较弱, 文献 <a href="#18">[18]</a> 使用逻辑回归分类器作为每层的弱分类器, 阈值依据曲线的 AUC(area under curve) 大小来设置, 增强了正样本通过的概率同时大大降低了负样本通过的概率, 减少了检测的阶段数目。 文献 <a href="#33">[33]</a> 通过推导提出了级联结构的两种一般化表示方式, 针对弱分类器叠加可能导致的局部最优问题, 提出了在强分类器上任意层动态加入最优弱分类器的算法, 尽可能保证了全局最优, 减少了弱分类器数目。</p>
<p>结合其他领域的算法为基于级联结构的人脸检测算法的未来改进提供了思路。 文献 <a href="#10">[10]</a><a href="#11">[11]</a> 结合文本检索技术, 弱分类器基于人脸词袋 (face examplar), 每一个弱分类器输出图像的人脸响应图, 累积这些响应图得到最后的人脸检测结果。相邻窗口的得分有一定的联系性, 单独处理每个窗口可能导致正样本过早地被去除, 在行人检测领域, 文献 <a href="#34">[34]</a> 在仿照人的神经递质提出了带有激活与抑制结构的人脸检测算法, 使得高得分附近的窗口得到增强, 而低得分附近的窗口得到抑制, 进一步提高检测的召回率和准确率, 为人脸检测算法提供了新思路。 非约束场景人脸形变较大, 人脸对齐方法 <a href="#35">[35]</a>-<a href="#38">[38]</a> 可以对人脸部位进行局部拟合得到人脸的特征点位置, 文献 <a href="#39">[39]</a> 创新性地将人脸检测与对齐方法进行结合, 在学习每棵决策树的同时, 将人脸特征点进行回归学习, 用人脸特征点指导分类器特征的选取。</p>
<h2 id="基于弹性不变模型的人脸检测算法"><a href="#基于弹性不变模型的人脸检测算法" class="headerlink" title="基于弹性不变模型的人脸检测算法"></a>基于弹性不变模型的人脸检测算法</h2><p>在非约束场景下, 人脸的表情、角度所带来的形变较大, 遮挡及光照变化会引入噪声。 基于级联结构的人脸检测算法往往是对预先学习到的位置提取分类特征, 对遮挡等噪声适应性较差。 另外,这些方法将不同表情、不同角度的人脸当成多个子类处理, 在预测时决策树每个节点将人脸划分到模式相同的簇 (batch) 提取特征, 对于形变过大的人脸, 决策树可能会将其划分到错误的节点上, 将其过早地过滤掉。</p>
<center><img src="/2016/06/07/人脸检测算法概述/4.png" alt=" TSM ">(a)文献 <a href="#9">[9]</a> 所使用的混合树模型示例<br><img src="/2016/06/07/人脸检测算法概述/5.png" alt=" MutiresHPM ">(b)文献 <a href="#40">[40]</a> 带遮挡特征点的人脸弹性模型示例。 红色为遮挡特征点, 绿色为可见特征点, 右图为人脸尺度较小时的模型<br>图 2-3 弹性不变模型示例<br><br></center>
<p>基于弹性不变模型 <a href="#7">[7]</a><a href="#8">[8]</a> 的人脸检测算法可以有效解决如遮挡、光照变化、表情变化、角度不一的问题。 这类方法将人脸定义为人脸不同部位 (parts) 的组合, 如鼻子、眼睛、嘴、耳朵等, 这些不同的部位通过“弹簧 (spring)”进行组合, 如图 2-3 所示。 这些人脸部位由非监督或者监督算法进行训练得到。 Latent SVM 分类器被训练来在人脸上找到这些部位及他们间的几何关系, 因此该类方法可以适应人脸的形变。 又由于是对局部部位进行特征提取, 因此, 这类方法还能检测到有部分遮挡的人脸 (如图 2-4 所示), 对人脸遮挡情况有很好的鲁棒性。</p>
<p>人脸检测算法需要的训练数据往往比较大, 在文献 <a href="#9">[9]</a> 中将人脸定义为若干个混合树模型, 每个子节点均由一个父节点关联, 只需要几百张标记有特征点位置的人脸训练数据就可以学习到不同模式的人脸, 而且在检测人脸的同时判断了人脸的角度及标定点的位置。 文献 <a href="#40">[40]</a> 在文献 <a href="#9">[9]</a> 基础上扩展了混合树模型来处理遮挡, 将人脸部位进行分级, 如眼睛、鼻子、嘴巴为一级, 这些位置附近的特征点为第二级, 如图 2-3(b)。 训练时随机生成带遮挡的人脸, 检测时当人脸某个部位被遮挡时, 对分类无效。 尽管这些变形采用了更加复杂的策略来处理人脸变形及遮挡, 文献 <a href="#28">[28]</a> 通过构建多个不同角度、不同尺度的弹性不变模型分别检测特定人脸, 取得了比文献 <a href="#9">[9]</a><a href="#41">[41]</a> 中复杂变形更好的效果。</p>
<center><img src="/2016/06/07/人脸检测算法概述/6.png" alt=" 弹性不变模型结果示例 "> 图 2-4 左图为文献 <a href="#9">[9]</a> 检测结果。 右图为文献 <a href="#40">[40]</a> 检测结果, 红色为遮挡人脸部位<br><br></center>
<p>基于弹性不变模型的人脸检测器计算量大, 主要由于:</p>
<ol>
<li>对于每个候选窗口都需要执行 Latent SVM 来寻找人脸部位;</li>
<li>为了可以处理不同角度的人脸检测,需要训练多个模型分别进行处理 <a href="#9">[9]</a><a href="#28">[28]</a><a href="#40">[40]</a><a href="#41">[41]</a><a href="#42">[42]</a>。 </li>
</ol>
<p>另外, 基于弹性不变模型的一些算法 <a href="#9">[9]</a><a href="#40">[40]</a> 需要训练数据集包含人脸特征点的标定, 建立这些数据集需要消耗大量人力物力。</p>
<h2 id="基于神经网络-深度学习的人脸检测算法"><a href="#基于神经网络-深度学习的人脸检测算法" class="headerlink" title="基于神经网络/深度学习的人脸检测算法"></a>基于神经网络/深度学习的人脸检测算法</h2><h3 id="卷积神经网络"><a href="#卷积神经网络" class="headerlink" title="卷积神经网络"></a>卷积神经网络</h3><p>传统人脸检测算法需要人工设计的特征, 需要大量专业领域知识, 线性分类器对人工提取的特征进行分类, 只能把样本分成简单的区域。 神经网络核心是通过使用自主学习过程来得到良好的特征 <a href="#43">[43]</a>。 由于梯度下降方法可能使得网络陷入局部最小值, 在 20 世纪 90 年代神经网络方法被研究者们所抛弃。 近年来,随着理论研究及实践表明, 大网络总是会得到差不多的解, 局部最小值并不会对网络整体性能造成很大影响 <a href="#20">[20]</a>。 同时, ReLU 非线性函数 <a href="#44">[44]</a> 的提出解决了梯度弥散问题, dropout 思想 <a href="#45">[45]</a> 的提出一定程度上解决了网络过拟合问题, 预训练 (pre-trained) 过程可以使得网络训练的效果更好的发现 <a href="#43">[43]</a>, 使得神经网络学习算法重新被研究者们关注。</p>
<p>卷积神经网络重新被计算机视觉团队及研究者们所重视是在 2012 年的百万图像规模数据竞赛 ImageNet 后, 该数据集包含 $ 1000 $ 个类别的物体, 深度卷积神经网络算法几乎比当时其他方法降低了 $ 50\% $ 的错误率 <a href="#43">[43]</a>。 卷积神经网络被设计成更容易地处理图像等多维数据, 其主要包含卷积层、归一化层、pooling层。</p>
<center><img src="/2016/06/07/人脸检测算法概述/7.png" alt=" 卷积层示例 "> 图2-5 卷积层示例, 其中, $ f_1, f_2, f_3 $为前一层的特征图,$ h_1, h_2 $ 为下一层输出的特征图<br><br></center>
<p>图像像素相邻位置具有很强的相关性, 对这些位置提取的特征表达性更强, 卷积神经网络使用卷积层实现这一功能, 卷积层如图 2-5 所示。 卷积层包含一组卷积核, 每个卷积核作用于前一层的特征图上, 上一层特征图的加权和得到下一层的特征图, 卷积核类似滤波操作。 卷积层是一种局部连接, 大大减少了全连接 (fully connected) 层的参数数目。 利用 ReLU 作为激活函数, 则卷积层特征图输出为:</p>
<p>$$ h_i = max(0, \sum_k f_k*w_i ) $$</p>
<p>其中为 $ w_i $ 当前层第 $ i $ 个卷积核, $ f_k $ 为前一层第 $ k $ 个特征图,$ h_i $为当前层第 $ i $ 个特征图输出。</p>
<p>归一化层往往接在卷积层后, 是对卷积层得到的特征图的归一化, 去除光照、线性噪声等外界因素的影响, 增强特征表达的适应性。</p>
<p>Pooling 层是为了让卷积层提取的特征更加鲁棒。 该层计算特征图局部最小邻域的最大值 (max-pooling) 或者平均值 (avg-pooling), 一方面对卷积层得到的特征进行了降维, 另一方面减少了噪声干扰, 使得特征更加突出。</p>
<h3 id="基于神经网络-深度学习的人脸检测算法-1"><a href="#基于神经网络-深度学习的人脸检测算法-1" class="headerlink" title="基于神经网络/深度学习的人脸检测算法"></a>基于神经网络/深度学习的人脸检测算法</h3><p>基于神经网络的人脸检测算法历史悠久 <a href="#46">[46]</a>-<a href="#53">[53]</a>。 文献 <a href="#46">[46]</a><a href="#47">[47]</a> 基于浅层卷积神经网络训练了一个两阶段人脸检测系统, 在第一个阶段, 训练了一个网络粗略定位人脸的位置, 第二个阶段则使用另外一个网络来验证这些位置是否包含人脸, 并调整了检测框。 单个网络可能得到局部最优值, 文献 <a href="#48">[48]</a> 在相同的训练数据集上分别采用不同的随机初始化参数训练了若干个浅层神经网络, 以此来避免该问题。 检测时图像被缩放到多个尺度上, 每个网络对图像输出人脸位置, 来自这些浅层神经网络的检测结果经过一系列的步骤进行融合, 得到了比单个网络更好的结果。</p>
<center><img src="/2016/06/07/人脸检测算法概述/8.png" alt=" DDFD示例 "> 图2-6 文献 <a href="#13">[13]</a> 网络输出的人脸概率分布图示例。 左图为原图, 右图为其概率分布图, 红色区域表示人脸出现概率高的区域, 蓝色则表示人脸出现概率低的区域(使用了网站<a href="https://github.com/guoyilin/FaceDetection_CNN" target="_blank" rel="external">https://github.com/guoyilin/FaceDetection_CNN</a> 的模型)。<br><br></center>
<p>更深的网络拥有更好的人脸检测性能。 文献 <a href="#49">[49]</a> 训练了单个浅层卷积神经网络来进行人脸检测, 该网络包含两层卷积层与 Pooling 层, 并通过权重共享将网络参数减少。 与过去方法只将人脸小范围旋转度进行训练集扩充不同, 在训练时, 该算法将人脸数据集左右旋转度及亮度归一化处理得到更多训练样本, 使得网络更加适应人脸的旋转和亮度变化。 文献 <a href="#53">[53]</a> 与文献 <a href="#49">[49]</a> 一样使用了两个卷积层和 Pooling 层, 不同的是创造性在浅层神经网络里引入了多任务损失函数进行学习, 该函数包含了两部分, 一部分为人脸检测的损失函数, 第二部分是人脸角度预测的损失函数。 通过这种方式, 神经网络不仅能检测到人脸, 还能预测出人脸所在的角度。</p>
<p>随着深度学习的重新兴起及 GPU 硬件的支持, 基于神经网络的人脸检测算法所使用的网络沿着更深更广的趋势发展。 文献<a href="#13">[13]</a> 在文献 <a href="#49">[49]</a> 的基础上, 使用 GPU 进行训练学习了更深的神经网络 AlexNet <a href="#12">[12]</a><a href="#14">[14]</a>, 其网络拥有五层卷积层和两层 Pooling 层。 与文献 <a href="#49">[49]</a> 相比, 最大不同在于:</p>
<ol>
<li>网络更深更广, 使用了 ReLU 非线性函数、dropout 函数进行训练;</li>
<li>使用了在超大型 ImageNet 数据集上预训练好的模型 AlexNet, 其模型本身初始化的权值拥有意义;</li>
<li>修改了全连接层使其可以输出每个位置上的人脸响应, 通过扫描窗口得到人脸的检测结果, 如图 2-6 所示;</li>
<li>使用了更大的数据集进行训练, 随机采样了 200,000 张人脸及 20,000,000 个负样本, 并为了保持训练数据均匀, 每批 (batch) 使用 32 个正样本及 96 个负样本进行训练。 </li>
</ol>
<p>文献 <a href="#13">[13]</a> 使用单一模型取得了与基于级联结构和弹性不变模型的人脸检测算法相似的检测效果。 多通道特征在人脸表示方面有比 HOG, SURF 等特征更强的表达性, 深度卷积网络学习到的人脸特征图是对人脸的高层次的抽象表示, 而分布式特征表示方式 (如图 2-7) 使得网络的权重能学习到人脸有显著特征的部位, 即能提取到局部特征。 文献<a href="#54">[54]</a> 进一步扩展了多通道特征为深度卷积网络学习到的特征图, 实验表明, 这些特征图比多通道特征有更好的表达性。</p>
<center><img src="/2016/06/07/人脸检测算法概述/9.png" alt=" 分布式特征表示方式 ">图 2-7 分布式特征表示方式<br><br></center>
<p>遵循 coarse-to-fine 原则是当前基于深度卷积网络的人脸检测算法的重要发展趋势。 基于级联结构的人脸检测算法 <a href="#39">[39]</a> 在检测人脸同时进行人脸标定点拟合来取得更好人脸检测框位置, 文献<a href="#55">[55]</a> 则提出了基于级联结构的卷积网络算法。 该算法同样在人脸检测时考虑到人脸矫正以获得更高性能, 共有三个阶段,每个阶段均包含有一个的检测网络, 后一阶段比前一阶段网络要更大, 分类性能更强。 每个阶段的网络输出会经过尺度、长宽、位置调整产生若干个候选区域再次进行检测, 保留得分比较好的区域作为下一阶段的输入, 以此将这些区域逐渐调整到更精确的人脸位置上。 Yang等人<a href="#56">[56]</a> 采用与文献 <a href="#46">[46]</a> 相似的策略, 提出了双阶段人脸检测器, 但深度要更加深, 对每个人脸部位生成响应图过滤得分过低的人脸候选区域, 如图 2-8, 并通过接在其后的检测网络得到对候选区域进行更加严格的分类与调整。</p>
<center><img src="/2016/06/07/人脸检测算法概述/10.png" alt=" 分布式特征表示方式 "> 图2-8 人脸部位响应图。 左上角为原图,从左到右从上到下分别为该图头发、眼睛、鼻子、嘴巴、下巴的响应图<br><br></center>
<h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><p>本文从三个分支上概述了人脸检测的算法。特征表达方面, 基于级联结构及弹性不变模型的人脸检测算法多是人工设计的, 而神经网络/深度学习则是通过网络学习人脸的特征图, 具有分布式特征表示方式。 尽管各个分支的处理方法不一, 但可以看到这三类方法的本质都是一样的, 都是提取人脸特征进行分类, 检测出图像中所有人脸出现的位置。 这三者基本的不同点在于, 基于级联结构的算法考虑到了图像中负样本数目庞大的因素, 在检测时把负样本更早地去除提高了整体检测的效率。 基于弹性不变模型的算法针对人脸各部分局部特征响应寻找图像中的人脸。 基于神经网络/深度学习的算法自主学习人脸局部及整体特征。</p>
<h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><ol>
<li><span id="1"> P. Viola, M. Jones. Rapid object detection using a boosted cascade of simple features[C], IEEE Conference on Computer Vision and Pattern Recognition, 2001, I-511~I-518 </span></li>
<li><span id="2"> P. Viola, M. Jones. Robust real-time face detection[J]. International Journal of Computer Vision, 57(2), 2004, 137-154 </span></li>
<li><span id="3"> R. Xiao, L. Zhu, H. Zhang. Boosting Chain Learning for Object Detection[C], IEEE International Conference on Computer Vision, 2003, 709~715 </span></li>
<li><span id="4"> R. Lienhart, J. Maydt. An Extended Set of Haar-like Features for Rapid Object Detection[C], IEEE International Conference on Image Processing, 2002, I-900~I-903 </span></li>
<li><span id="5"> R. Lienhart, A. Kuranov, V. Pisarevsky. Empirical Analysis of Detection Cascades of Boosted Classifiers for Rapid Object Detection[C], Pattern Recognition, Springer, 2003, 297~304 </span></li>
<li><span id="6"> M. Jones, P. Viola. Fast multi-view face detection[C], IEEE Conference on Computer Vision and Pattern Recognition, 2003 </span></li>
<li><span id="7"> P. F. Felzenszwalb, D. P. Huttenlocher. Pictorial Structures for Object Recognition[J], International Journal of Computer Vision, Vol. 61, No. 1, 2005, 55~79 </span></li>
<li><span id="8"> P. F. Felzenszwalb, R. B. Girshick, D. McAllester, D. Ramanan. Object Detection with Discriminatively Trained Part-Based Models[J], IEEE Transactions on Pattern Analysis and Machine Intelligence, Vol. 32, No. 9, 2010, 1627~1645 </span></li>
<li><span id="9"> X. Zhu, D. Ramanan. Face detection, pose estimation, and landmark localization in the wild[C], IEEE Conference on Computer Vision and Pattern Recognition, 2012, 2879~2886 </span></li>
<li><span id="10"> X. Shen, Z. Lin, J. Brandt, Y. Wu. Detecting and Aligning Faces by Image Retrieval[C], IEEE Conference on Computer Vision and Pattern Recognition, 2013, 3460~3467 </span></li>
<li><span id="11"> H. Li, Z. Lin, J. Brandt, X. Shen, G. Hua. Efficient Boosted Exemplar-based Face Detection[C], IEEE Conference on Computer Vision and Pattern Recognition, 2014, 1843~1850 </span></li>
<li><span id="12"> A. Krizhevsky, I. Sutskever, G. E. Hinton. ImageNet Classification with Deep Convolutional Neural Networks[C], 2012, 1097~1105 </span></li>
<li><span id="13"> S. S. Farfade, M. Saberian, L. Li. Multi-view Face Detection Using Deep Convolutional Neural Networks[C], 5th ACM International Conference on Multimedia Retrieval, 2015, 643~650 </span></li>
<li><span id="14"> R. Girshick, J. Donahue, T. Darrell, J. Malik. Rich feature hierarchies for accurate object detection and semantic segmentation[C], IEEE Conference on Computer Vision and Pattern Recognition, 2014, 580~587 </span></li>
<li><span id="15"> N. Markus, M. Frljak, I. S. Pandzic, J. Ahlberg and R. Forchheimer. A Method for Object Detection Based on Pixel Intensity Comparisons Organized in Decision Trees[J], arXiv preprint arXiv:1305.4537, 2013 </span></li>
<li><span id="16"> L. Shengcai, A. K. Jain, and S. Z. Li. Unconstrained face detection, Technical report, Michigan State University, Dec.2012 </span></li>
<li><span id="17"> B. Yang, J. Yan, Z. Lei, S. Z. Li. Aggregate channel features for multi-view face detection[C], IEEE International Joint Conference on Biometrics, 2014, 1~8 </span></li>
<li><span id="18"> J. Li, Y. Zhang. Learning SURF Cascade for Fast and Accurate Object Detection[C], IEEE Conference on Computer Vision and Pattern Recognition, 2013, 3468~3475 </span></li>
<li><span id="19"> H. A. Rowley, S. Baluja, T. Kanade. Neural network-based face detection[C], IEEE Conference on Computer Vision and Pattern Recognition, 1996, 203~208 </span> </li>
<li><span id="20"> Y. Dauphin, R. Pascanu, C. Gulcehre, K. Cho, S. Ganguli, Y. Bengio. Identifying and attacking the saddle point problem in high-dimensional non-convex optimization[C], Neural Information Processing Systems, 2014, 2933~2941 </span></li>
<li><span id="21"> S. Liao, A. K. Jain, S. Z. Li. A Fast and Accurate Unconstrained Face Detector[J], IEEE Transactions on Pattern Analysis and Machine Intelligence, Vol. 38, No. 2, 2016, 211~223 </span></li>
<li><span id="22"> Y. Freund, R. E Schapire. A Decision-Theoretic Generalization of On-Line Learning and an Application to Boosting[J], Journal of computer and system sciences, Vol. 55, No. 1, 1997, 119~139 </span></li>
<li><span id="23"> J. Li, T. Wang, Y. Zhang. Face detection using SURF cascade[C], IEEE International Conference on Computer Vision, 2011, 2183~2190 </span></li>
<li><span id="24"> L. Bourdev, J. Brandt. Robust Object Detection Via Soft Cascade[C], IEEE Conference on Computer Vision and Pattern Recognition, 2005, 236~243 </span></li>
<li><span id="25"> H. Bay, A. Ess, T. Tuytelaars, L. Van Gool. Speeded-Up Robust Features (SURF)[J], Computer Vision and Image Understanding, Vol. 10, No. 3, 2008, 346~359 </span></li>
<li><span id="26"> J. Wu, N. Liu, C. Geyer, J. M. Rehg. C4 : A Real-Time Object Detection Framework[J], IEEE Transactions on Image Processing, Vol. 22, No. 10, 2013, 4096~4107 </span></li>
<li><span id="27"> T. Ojala, M. Pietikäinen, D. Harwood. A comparative study of texture measures with classification based on featured distributions, Pattern Recognition, Vol. 29, No. 1, 1996, 51~59 </span></li>
<li><span id="28"> M. Mathias, R. Benenson, M. Pedersoli, L. Van Gool. Face detection without bells and whistles[C], European Conference on Computer Vision, 2014, 720~735 </span></li>
<li><span id="29"> P. Dollár1, Z. Tu, P. Perona, S. Belongie. Integral channel features[C], British Machine Vision Conference, 2009, 91.1~91.11 </span></li>
<li><span id="30"> N. Dalal, B. Triggs. Histograms of Oriented Gradients for Human Detection[C], IEEE Conference on Computer Vision and Pattern Recognition, 2005, 886~893 </span></li>
<li><span id="31"> P. Dollár, R. Appel, S. Belongie, P. Perona. Fast Feature Pyramids for Object Detection[J], IEEE Transactions on Pattern Analysis and Machine Intelligence, Vol. 36, No. 8, 2014, 1532~1545 </span></li>
<li><span id="32"> P. Viola, M. Jones. Fast and Robust Classification using Asymmetric AdaBoost and a Detector Cascade[C], Neural Information Processing Systems, 2002, 1311~1318 </span> </li>
<li><span id="33"> M. Saberian, N. Vasconcelos. Boosting Algorithms for Detector Cascade Learning[J], Journal of Machine Learning Research, Vol. 15, No. 1, 2014, 2569~2605 </span></li>
<li><span id="34"> P. Dollár, R. Appel, W. Kienzle. Crosstalk Cascades for Frame-Rate Pedestrian Detection[C], European Conference on Computer Vision, 2012, 645~659 </span></li>
<li><span id="35"> S. Ren, X. Cao, Y. Wei, J. Sun. Face Alignment at 3000 FPS via Regressing Local Binary Features[C], IEEE Conference on Computer Vision and Pattern Recognition, 2014, 1685~1692</span></li>
<li><span id="36"> X. Cao, Y. Wei, F. Wen, J. Sun. Face Alignment by Explicit Shape Regression[C], IEEE Conference on Computer Vision and Pattern Recognition, 2012, 2887~2894 </span></li>
<li><span id="37"> X. P. Burgos-Artizzu, P. Perona, P. Dollár. Robust face landmark estimation under occlusion[C], IEEE International Conference on Computer Vision, 2012, 1513~1520 </span></li>
<li><span id="38"> P. Dollár, P. Welinder, P. Perona. Cascaded Pose Regression[C], IEEE Conference on Computer Vision and Pattern Recognition, 2010, 1078~1085 </span></li>
<li><span id="39"> D. Chen, S. Ren, Y. Wei, X. Cao, J. Sun. Joint Cascade Face Detection and Alignment[C], European Conference on Computer Vision, 2014, 109~122 </span> </li>
<li><span id="40"> G. Ghiasi, C. C. Fowlkes. Occlusion Coherence: Detecting and Localizing Occluded Faces[J], arXiv preprint arXiv:1506.08347, 2015 </span></li>
<li><span id="41"> J. Yan, X. Zhang, Z. Lei, S. Z. Li. Face detection by structural models[J], Image and Vision Computing, Vol. 32, No. 10, 2014, 790~799 </span></li>
<li><span id="42"> J. Yan, Z. Lei, L. Wen, S. Z. Li. The Fastest Deformable Part Model for Object Detection[C], IEEE Conference on Computer Vision and Pattern Recognition, 2014, 2497~2504 </span></li>
<li><span id="43"> Y. LeCun, Y. Bengio, G. Hinton. Deep learning[J], Nature, Vol. 521, No. 7553, 2015, 436~444 </span></li>
<li><span id="44"> X. Glorot, A. Bordes, Y. Bengio. Deep Sparse Rectifier Neural Networks[J], Journal of Machine Learning Research[J], 2011, 315~323 </span></li>
<li><span id="45"> G. E. Hinton, N. Srivastava, A. Krizhevsky, I. Sutskever, R. R. Salakhutdinov. Improving neural networks by preventing co-adaptation of feature detectors[J], arXiv preprint arXiv:1207.0580, 2012 </span></li>
<li><span id="46"> R. Vaillant, C. Monrocq, Y. Le Cun. An original approach for the localization of objects in images[C], IEEE International Conference on Articial Neural Networks, 1993, 26~30 </span></li>
<li><span id="47"> R. Vaillant, C. Monrocq, Y. Le Cun. Original approach for the localisation of objects in images[J], Vision, Image and Signal Processing, Vol. 141, No. 4, 1994, 245~250 </span></li>
<li><span id="48"> H. A. Rowley, S. Baluja, T. Kanade. Neural network-based face detection[C], IEEE Conference on Computer Vision and Pattern Recognition, 1996, 203~208 </span></li>
<li><span id="49"> C. Garcia, M. Delakis. A Neural Architecture for Fast and Robust Face Detection[C], IEEE International Conference on Pattern Recognition, 2002, 44~47 </span></li>
<li><span id="50"> M. Delakis, C. Garcia. Training Convolutional Filters for Robust Face Detection[C], IEEE International Workshop of Neural Networks for Signal Processing, 2003, 739~748 </span></li>
<li><span id="51"> C. Garcia, M. Delakis. Convolutional face finder: a neural architecture for fast and robust face detection[J], IEEE Transactions on Pattern Analysis and Machine Intelligence, Vol. 26, No. 11, 2004, 1408~1423 </span></li>
<li><span id="52"> S. Roux, F. Mamalet, C. Garcia. Embedded Convolutional Face Finder[C], IEEE International Conference on Multimedia and Expo, 2006, 285~288 </span></li>
<li><span id="53"> M. Osadchy, Y. Le Cun, M. L. Miller. Synergistic Face Detection and Pose Estimation with Energy-Based Models[J], Journal of Machine Learning Research, Vol. 8, No. 1, 2007, 1017~1024 </span></li>
<li><span id="54"> B. Yang, J. Yan, Z. Lei, S. Z. Li. Convolutional channel features[C], IEEE International Conference on Computer Vision, 2015, 82~90 </span></li>
<li><span id="55"> H. Li, Z. Lin, X. Shen, J. Brandt, G. Hua. A convolutional neural network cascade for face detection[C], IEEE Conference on Computer Vision and Pattern Recognition, 2015, 5325~5334 </span></li>
<li><span id="56"> S. Yang, P. Luo, C. C. Loy, X. Tang. From facial parts responses to face detection: A deep learning approach[C], IEEE International Conference on Computer Vision, 2015, 3676~3684 </span></li>
</ol>
]]></content>
</entry>
</search>