]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/smart_ptr/sp_techniques.html
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / smart_ptr / sp_techniques.html
CommitLineData
7c673cae
FG
1<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 <title>Smart Pointer Programming Techniques</title>
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
6 </head>
7 <body text="#000000" bgcolor="#ffffff" link="#0000ff" vlink="#0000ff">
8 <h1><img height="86" alt="boost.png (6897 bytes)" src="../../boost.png"
9 width="277" align="middle" border="0">Smart Pointer Programming Techniques</h1>
10 <p><A href="#incomplete">Using incomplete classes for implementation hiding</A><br>
11 <A href="#pimpl">The "Pimpl" idiom</A><br>
12 <A href="#abstract">Using abstract classes for implementation hiding</A><br>
13 <A href="#preventing_delete">Preventing <code>delete px.get()</code></A><br>
14 <A href="#array">Using a <code>shared_ptr</code> to hold a pointer to an array</A><br>
15 <A href="#encapsulation">Encapsulating allocation details, wrapping factory
16 functions</A><br>
17 <A href="#static">Using a <code>shared_ptr</code> to hold a pointer to a statically
18 allocated object</A><br>
19 <A href="#com">Using a <code>shared_ptr</code> to hold a pointer to a COM object</A><br>
20 <A href="#intrusive">Using a <code>shared_ptr</code> to hold a pointer to an object
21 with an embedded reference count</A><br>
22 <A href="#another_sp">Using a <code>shared_ptr</code> to hold another shared
23 ownership smart pointer</A><br>
24 <A href="#from_raw">Obtaining a <code>shared_ptr</code> from a raw pointer</A><br>
25 <A href="#in_constructor">Obtaining a <code>shared_ptr</code> (<code>weak_ptr</code>)
26 to <code>this</code> in a constructor</A><br>
27 <A href="#from_this">Obtaining a <code>shared_ptr</code> to <code>this</code></A><br>
28 <A href="#handle">Using <code>shared_ptr</code> as a smart counted handle</A><br>
29 <A href="#on_block_exit">Using <code>shared_ptr</code> to execute code on block
30 exit</A><br>
31 <A href="#pvoid">Using <code>shared_ptr&lt;void&gt;</code> to hold an arbitrary
32 object</A><br>
33 <A href="#extra_data">Associating arbitrary data with heterogeneous <code>shared_ptr</code>
34 instances</A><br>
35 <A href="#as_lock">Using <code>shared_ptr</code> as a CopyConstructible mutex lock</A><br>
36 <A href="#wrapper">Using <code>shared_ptr</code> to wrap member function calls</A><br>
37 <A href="#delayed">Delayed deallocation</A><br>
38 <A href="#weak_without_shared">Weak pointers to objects not managed by a <code>shared_ptr</code></A><br>
39 </p>
40 <h2><A name="incomplete">Using incomplete classes for implementation hiding</A></h2>
41 <p>A proven technique (that works in C, too) for separating interface from
42 implementation is to use a pointer to an incomplete class as an opaque handle:</p>
43 <pre>class FILE;
44
45FILE * fopen(char const * name, char const * mode);
46void fread(FILE * f, void * data, size_t size);
47void fclose(FILE * f);
48</pre>
49 <p>It is possible to express the above interface using <code>shared_ptr</code>,
50 eliminating the need to manually call <code>fclose</code>:</p>
51 <pre>class FILE;
52
53shared_ptr&lt;FILE&gt; fopen(char const * name, char const * mode);
54void fread(shared_ptr&lt;FILE&gt; f, void * data, size_t size);
55</pre>
56 <p>This technique relies on <code>shared_ptr</code>'s ability to execute a custom
57 deleter, eliminating the explicit call to <code>fclose</code>, and on the fact
58 that <code>shared_ptr&lt;X&gt;</code> can be copied and destroyed when <code>X</code>
59 is incomplete.</p>
60 <h2><A name="pimpl">The "Pimpl" idiom</A></h2>
61 <p>A C++ specific variation of the incomplete class pattern is the "Pimpl" idiom.
62 The incomplete class is not exposed to the user; it is hidden behind a
63 forwarding facade. <code>shared_ptr</code> can be used to implement a "Pimpl":</p>
64 <pre>// file.hpp:
65
66class file
67{
68private:
69
70 class impl;
71 shared_ptr&lt;impl&gt; pimpl_;
72
73public:
74
75 file(char const * name, char const * mode);
76
77 // compiler generated members are fine and useful
78
79 void read(void * data, size_t size);
80};
81</pre>
82 <pre>// file.cpp:
83
84#include "file.hpp"
85
86class file::impl
87{
88private:
89
90 impl(impl const &amp;);
91 impl &amp; operator=(impl const &amp;);
92
93 // private data
94
95public:
96
97 impl(char const * name, char const * mode) { ... }
98 ~impl() { ... }
99 void read(void * data, size_t size) { ... }
100};
101
102file::file(char const * name, char const * mode): pimpl_(new impl(name, mode))
103{
104}
105
106void file::read(void * data, size_t size)
107{
108 pimpl_-&gt;read(data, size);
109}
110</pre>
111 <p>The key thing to note here is that the compiler-generated copy constructor,
112 assignment operator, and destructor all have a sensible meaning. As a result, <code>
113 file</code> is <code>CopyConstructible</code> and <code>Assignable</code>,
114 allowing its use in standard containers.</p>
115 <h2><A name="abstract">Using abstract classes for implementation hiding</A></h2>
116 <p>Another widely used C++ idiom for separating inteface and implementation is to
117 use abstract base classes and factory functions. The abstract classes are
118 sometimes called "interfaces" and the pattern is known as "interface-based
119 programming". Again, <code>shared_ptr</code> can be used as the return type of
120 the factory functions:</p>
121 <pre>// X.hpp:
122
123class X
124{
125public:
126
127 virtual void f() = 0;
128 virtual void g() = 0;
129
130protected:
131
132 ~X() {}
133};
134
135shared_ptr&lt;X&gt; createX();
136</pre>
137 <pre>-- X.cpp:
138
139class X_impl: public X
140{
141private:
142
143 X_impl(X_impl const &amp;);
144 X_impl &amp; operator=(X_impl const &amp;);
145
146public:
147
148 virtual void f()
149 {
150 // ...
151 }
152
153 virtual void g()
154 {
155 // ...
156 }
157};
158
159shared_ptr&lt;X&gt; createX()
160{
161 shared_ptr&lt;X&gt; px(new X_impl);
162 return px;
163}
164</pre>
165 <p>A key property of shared_ptr is that the allocation, construction, deallocation,
166 and destruction details are captured at the point of construction, inside the
167 factory function. Note the protected and nonvirtual destructor in the example
168 above. The client code cannot, and does not need to, delete a pointer to <code>X</code>;
169 the <code>shared_ptr&lt;X&gt;</code> instance returned from <code>createX</code>
170 will correctly call <code>~X_impl</code>.</p>
171 <h2><A name="preventing_delete">Preventing <code>delete px.get()</code></A></h2>
172 <p>It is often desirable to prevent client code from deleting a pointer that is
173 being managed by <code>shared_ptr</code>. The previous technique showed one
174 possible approach, using a protected destructor. Another alternative is to use
175 a private deleter:</p>
176 <pre>class X
177{
178private:
179
180 ~X();
181
182 class deleter;
183 friend class deleter;
184
185 class deleter
186 {
187 public:
188
189 void operator()(X * p) { delete p; }
190 };
191
192public:
193
194 static shared_ptr&lt;X&gt; create()
195 {
196 shared_ptr&lt;X&gt; px(new X, X::deleter());
197 return px;
198 }
199};
200</pre>
201 <h2><A name="array">Using a <code>shared_ptr</code> to hold a pointer to an array</A></h2>
202 <p>A <code>shared_ptr</code> can be used to hold a pointer to an array allocated
203 with <code>new[]</code>:</p>
204 <pre>shared_ptr&lt;X&gt; px(new X[1], <A href="../utility/checked_delete.html" >checked_array_deleter</A>&lt;X&gt;());
205</pre>
206 <p>Note, however, that <code><A href="shared_array.htm">shared_array</A></code> is
207 often preferable, if this is an option. It has an array-specific interface,
208 without <code>operator*</code> and <code>operator-&gt;</code>, and does not
209 allow pointer conversions.</p>
210 <h2><A name="encapsulation">Encapsulating allocation details, wrapping factory
211 functions</A></h2>
212 <p><code>shared_ptr</code> can be used in creating C++ wrappers over existing C
213 style library interfaces that return raw pointers from their factory functions
214 to encapsulate allocation details. As an example, consider this interface,
215 where <code>CreateX</code> might allocate <code>X</code> from its own private
216 heap, <code>~X</code> may be inaccessible, or <code>X</code> may be incomplete:</p>
217 <pre>X * CreateX();
218void DestroyX(X *);
219</pre>
220 <p>The only way to reliably destroy a pointer returned by <code>CreateX</code> is
221 to call <code>DestroyX</code>.</p>
222 <P>Here is how a <code>shared_ptr</code>-based wrapper may look like:</P>
223 <pre>shared_ptr&lt;X&gt; createX()
224{
225 shared_ptr&lt;X&gt; px(CreateX(), DestroyX);
226 return px;
227}
228</pre>
229 <p>Client code that calls <code>createX</code> still does not need to know how the
230 object has been allocated, but now the destruction is automatic.</p>
231 <h2><A name="static">Using a <code>shared_ptr</code> to hold a pointer to a statically
232 allocated object</A></h2>
233 <p>Sometimes it is desirable to create a <code>shared_ptr</code> to an already
234 existing object, so that the <code>shared_ptr</code> does not attempt to
235 destroy the object when there are no more references left. As an example, the
236 factory function:</p>
237 <pre>shared_ptr&lt;X&gt; createX();
238</pre>
239 <p>in certain situations may need to return a pointer to a statically allocated <code>X</code>
240 instance.</p>
241 <P>The solution is to use a custom deleter that does nothing:</P>
242 <pre>struct null_deleter
243{
244 void operator()(void const *) const
245 {
246 }
247};
248
249static X x;
250
251shared_ptr&lt;X&gt; createX()
252{
253 shared_ptr&lt;X&gt; px(&amp;x, null_deleter());
254 return px;
255}
256</pre>
257 <p>The same technique works for any object known to outlive the pointer.</p>
258 <h2><A name="com">Using a <code>shared_ptr</code> to hold a pointer to a COM Object</A></h2>
259 <p>Background: COM objects have an embedded reference count and two member
260 functions that manipulate it. <code>AddRef()</code> increments the count. <code>Release()</code>
261 decrements the count and destroys itself when the count drops to zero.</p>
262 <P>It is possible to hold a pointer to a COM object in a <code>shared_ptr</code>:</P>
263 <pre>shared_ptr&lt;IWhatever&gt; make_shared_from_COM(IWhatever * p)
264{
265 p-&gt;AddRef();
266 shared_ptr&lt;IWhatever&gt; pw(p, <A href="../bind/mem_fn.html" >mem_fn</A>(&amp;IWhatever::Release));
267 return pw;
268}
269</pre>
270 <p>Note, however, that <code>shared_ptr</code> copies created from <code>pw</code> will
271 not "register" in the embedded count of the COM object; they will share the
272 single reference created in <code>make_shared_from_COM</code>. Weak pointers
273 created from <code>pw</code> will be invalidated when the last <code>shared_ptr</code>
274 is destroyed, regardless of whether the COM object itself is still alive.</p>
275 <P>As <A href="../bind/mem_fn.html#Q3">explained</A> in the <code>mem_fn</code> documentation,
276 you need to <A href="../bind/mem_fn.html#stdcall">#define
277 BOOST_MEM_FN_ENABLE_STDCALL</A> first.</P>
278 <h2><A name="intrusive">Using a <code>shared_ptr</code> to hold a pointer to an object
279 with an embedded reference count</A></h2>
280 <p>This is a generalization of the above technique. The example assumes that the
281 object implements the two functions required by <code><A href="intrusive_ptr.html">intrusive_ptr</A></code>,
282 <code>intrusive_ptr_add_ref</code> and <code>intrusive_ptr_release</code>:</p>
283 <pre>template&lt;class T&gt; struct intrusive_deleter
284{
285 void operator()(T * p)
286 {
287 if(p) intrusive_ptr_release(p);
288 }
289};
290
291shared_ptr&lt;X&gt; make_shared_from_intrusive(X * p)
292{
293 if(p) intrusive_ptr_add_ref(p);
294 shared_ptr&lt;X&gt; px(p, intrusive_deleter&lt;X&gt;());
295 return px;
296}
297</pre>
298 <h2><A name="another_sp">Using a <code>shared_ptr</code> to hold another shared
299 ownership smart pointer</A></h2>
300 <p>One of the design goals of <code>shared_ptr</code> is to be used in library
301 interfaces. It is possible to encounter a situation where a library takes a <code>shared_ptr</code>
302 argument, but the object at hand is being managed by a different reference
303 counted or linked smart pointer.</p>
304 <P>It is possible to exploit <code>shared_ptr</code>'s custom deleter feature to
305 wrap this existing smart pointer behind a <code>shared_ptr</code> facade:</P>
306 <pre>template&lt;class P&gt; struct smart_pointer_deleter
307{
308private:
309
310 P p_;
311
312public:
313
314 smart_pointer_deleter(P const &amp; p): p_(p)
315 {
316 }
317
318 void operator()(void const *)
319 {
320 p_.reset();
321 }
322
323 P const &amp; get() const
324 {
325 return p_;
326 }
327};
328
329shared_ptr&lt;X&gt; make_shared_from_another(another_ptr&lt;X&gt; qx)
330{
331 shared_ptr&lt;X&gt; px(qx.get(), smart_pointer_deleter&lt; another_ptr&lt;X&gt; &gt;(qx));
332 return px;
333}
334</pre>
335 <p>One subtle point is that deleters are not allowed to throw exceptions, and the
336 above example as written assumes that <code>p_.reset()</code> doesn't throw. If
337 this is not the case, <code>p_.reset()</code> should be wrapped in a <code>try {}
338 catch(...) {}</code> block that ignores exceptions. In the (usually
339 unlikely) event when an exception is thrown and ignored, <code>p_</code> will
340 be released when the lifetime of the deleter ends. This happens when all
341 references, including weak pointers, are destroyed or reset.</p>
342 <P>Another twist is that it is possible, given the above <code>shared_ptr</code> instance,
343 to recover the original smart pointer, using <code><A href="shared_ptr.htm#get_deleter">
344 get_deleter</A></code>:</P>
345 <pre>void extract_another_from_shared(shared_ptr&lt;X&gt; px)
346{
347 typedef smart_pointer_deleter&lt; another_ptr&lt;X&gt; &gt; deleter;
348
349 if(deleter const * pd = get_deleter&lt;deleter&gt;(px))
350 {
351 another_ptr&lt;X&gt; qx = pd-&gt;get();
352 }
353 else
354 {
355 // not one of ours
356 }
357}
358</pre>
359 <h2><A name="from_raw">Obtaining a <code>shared_ptr</code> from a raw pointer</A></h2>
360 <p>Sometimes it is necessary to obtain a <code>shared_ptr</code> given a raw
361 pointer to an object that is already managed by another <code>shared_ptr</code>
362 instance. Example:</p>
363 <pre>void f(X * p)
364{
365 shared_ptr&lt;X&gt; px(<i>???</i>);
366}
367</pre>
368 <p>Inside <code>f</code>, we'd like to create a <code>shared_ptr</code> to <code>*p</code>.</p>
369 <P>In the general case, this problem has no solution. One approach is to modify <code>f</code>
370 to take a <code>shared_ptr</code>, if possible:</P>
371 <pre>void f(shared_ptr&lt;X&gt; px);
372</pre>
373 <p>The same transformation can be used for nonvirtual member functions, to convert
374 the implicit <code>this</code>:</p>
375 <pre>void X::f(int m);
376</pre>
377 <p>would become a free function with a <code>shared_ptr</code> first argument:</p>
378 <pre>void f(shared_ptr&lt;X&gt; this_, int m);
379</pre>
380 <p>If <code>f</code> cannot be changed, but <code>X</code> uses intrusive counting,
381 use <code><A href="#intrusive">make_shared_from_intrusive</A></code> described
382 above. Or, if it's known that the <code>shared_ptr</code> created in <code>f</code>
383 will never outlive the object, use <A href="#static">a null deleter</A>.</p>
384 <h2><A name="in_constructor">Obtaining a <code>shared_ptr</code> (<code>weak_ptr</code>)
385 to <code>this</code> in a constructor</A></h2>
386 <p>Some designs require objects to register themselves on construction with a
387 central authority. When the registration routines take a shared_ptr, this leads
388 to the question how could a constructor obtain a shared_ptr to this:</p>
389 <pre>class X
390{
391public:
392
393 X()
394 {
395 shared_ptr&lt;X&gt; this_(<i>???</i>);
396 }
397};
398</pre>
399 <p>In the general case, the problem cannot be solved. The <code>X</code> instance
400 being constructed can be an automatic variable or a static variable; it can be
401 created on the heap:</p>
402 <pre>shared_ptr&lt;X&gt; px(new X);</pre>
403 <P>but at construction time, <code>px</code> does not exist yet, and it is
404 impossible to create another <code>shared_ptr</code> instance that shares
405 ownership with it.</P>
406 <P>Depending on context, if the inner <code>shared_ptr</code> <code>this_</code> doesn't
407 need to keep the object alive, use a <code>null_deleter</code> as explained <A href="#static">
408 here</A> and <A href="#weak_without_shared">here</A>. If <code>X</code> is
409 supposed to always live on the heap, and be managed by a <code>shared_ptr</code>,
410 use a static factory function:</P>
411 <pre>class X
412{
413private:
414
415 X() { ... }
416
417public:
418
419 static shared_ptr&lt;X&gt; create()
420 {
421 shared_ptr&lt;X&gt; px(new X);
422 // use px as 'this_'
423 return px;
424 }
425};
426</pre>
427 <h2><A name="from_this">Obtaining a <code>shared_ptr</code> to <code>this</code></A></h2>
428 <p>Sometimes it is needed to obtain a <code>shared_ptr</code> from <code>this</code>
429 in a virtual member function under the assumption that <code>this</code> is
430 already managed by a <code>shared_ptr</code>. The transformations <A href="#from_raw">
431 described in the previous technique</A> cannot be applied.</p>
432 <P>A typical example:</P>
433 <pre>class X
434{
435public:
436
437 virtual void f() = 0;
438
439protected:
440
441 ~X() {}
442};
443
444class Y
445{
446public:
447
448 virtual shared_ptr&lt;X&gt; getX() = 0;
449
450protected:
451
452 ~Y() {}
453};
454
455// --
456
457class impl: public X, public Y
458{
459public:
460
461 impl() { ... }
462
463 virtual void f() { ... }
464
465 virtual shared_ptr&lt;X&gt; getX()
466 {
467 shared_ptr&lt;X&gt; px(<i>???</i>);
468 return px;
469 }
470};
471</pre>
472 <p>The solution is to keep a weak pointer to <code>this</code> as a member in <code>impl</code>:</p>
473 <pre>class impl: public X, public Y
474{
475private:
476
477 weak_ptr&lt;impl&gt; weak_this;
478
479 impl(impl const &amp;);
480 impl &amp; operator=(impl const &amp;);
481
482 impl() { ... }
483
484public:
485
486 static shared_ptr&lt;impl&gt; create()
487 {
488 shared_ptr&lt;impl&gt; pi(new impl);
489 pi-&gt;weak_this = pi;
490 return pi;
491 }
492
493 virtual void f() { ... }
494
495 virtual shared_ptr&lt;X&gt; getX()
496 {
497 shared_ptr&lt;X&gt; px(weak_this);
498 return px;
499 }
500};
501</pre>
502 <p>The library now includes a helper class template <code><A href="enable_shared_from_this.html">
503 enable_shared_from_this</A></code> that can be used to encapsulate the
504 solution:</p>
505 <pre>class impl: public X, public Y, public enable_shared_from_this&lt;impl&gt;
506{
507public:
508
509 impl(impl const &amp;);
510 impl &amp; operator=(impl const &amp;);
511
512public:
513
514 virtual void f() { ... }
515
516 virtual shared_ptr&lt;X&gt; getX()
517 {
518 return shared_from_this();
519 }
520}
521</pre>
522 <p>Note that you no longer need to manually initialize the <code>weak_ptr</code> member
523 in <code><A href="enable_shared_from_this.html">enable_shared_from_this</A></code>.
524 Constructing a <code>shared_ptr</code> to <code>impl</code> takes care of that.</p>
525 <h2><A name="handle">Using <code>shared_ptr</code> as a smart counted handle</A></h2>
526 <p>Some library interfaces use opaque handles, a variation of the <A href="#incomplete">
527 incomplete class technique</A> described above. An example:</p>
528 <pre>typedef void * HANDLE;
529HANDLE CreateProcess();
530void CloseHandle(HANDLE);
531</pre>
532 <p>Instead of a raw pointer, it is possible to use <code>shared_ptr</code> as the
533 handle and get reference counting and automatic resource management for free:</p>
534 <pre>typedef shared_ptr&lt;void&gt; handle;
535
536handle createProcess()
537{
538 shared_ptr&lt;void&gt; pv(CreateProcess(), CloseHandle);
539 return pv;
540}
541</pre>
542 <h2><A name="on_block_exit">Using <code>shared_ptr</code> to execute code on block exit</A></h2>
543 <p><code>shared_ptr&lt;void&gt;</code> can automatically execute cleanup code when
544 control leaves a scope.</p>
545 <UL>
546 <LI>
547 Executing <code>f(p)</code>, where <code>p</code> is a pointer:</LI></UL>
548 <pre> shared_ptr&lt;void&gt; guard(p, f);
549</pre>
550 <UL>
551 <LI>
552 Executing arbitrary code: <code>f(x, y)</code>:</LI></UL>
553 <pre> shared_ptr&lt;void&gt; guard(static_cast&lt;void*&gt;(0), <A href="../bind/bind.html" >bind</A>(f, x, y));
554</pre>
555 <P>For a more thorough treatment, see the article "Simplify Your Exception-Safe
556 Code" by Andrei Alexandrescu and Petru Marginean, available online at <A href="http://www.cuj.com/experts/1812/alexandr.htm?topic=experts">
557 http://www.cuj.com/experts/1812/alexandr.htm?topic=experts</A>.</P>
558 <h2><A name="pvoid">Using <code>shared_ptr&lt;void&gt;</code> to hold an arbitrary
559 object</A></h2>
560 <p><code>shared_ptr&lt;void&gt;</code> can act as a generic object pointer similar
561 to <code>void*</code>. When a <code>shared_ptr&lt;void&gt;</code> instance
562 constructed as:</p>
563 <pre> shared_ptr&lt;void&gt; pv(new X);
564</pre>
565 <p>is destroyed, it will correctly dispose of the <code>X</code> object by
566 executing <code>~X</code>.</p>
567 <p>This propery can be used in much the same manner as a raw <code>void*</code> is
568 used to temporarily strip type information from an object pointer. A <code>shared_ptr&lt;void&gt;</code>
569 can later be cast back to the correct type by using <code><A href="shared_ptr.htm#static_pointer_cast">
570 static_pointer_cast</A></code>.</p>
571 <h2><A name="extra_data">Associating arbitrary data with heterogeneous <code>shared_ptr</code>
572 instances</A></h2>
573 <p><code>shared_ptr</code> and <code>weak_ptr</code> support <code>operator&lt;</code>
574 comparisons required by standard associative containers such as <code>std::map</code>.
575 This can be used to non-intrusively associate arbitrary data with objects
576 managed by <code>shared_ptr</code>:</p>
577 <pre>typedef int Data;
578
579std::map&lt; shared_ptr&lt;void&gt;, Data &gt; userData;
580// or std::map&lt; weak_ptr&lt;void&gt;, Data &gt; userData; to not affect the lifetime
581
582shared_ptr&lt;X&gt; px(new X);
583shared_ptr&lt;int&gt; pi(new int(3));
584
585userData[px] = 42;
586userData[pi] = 91;
587</pre>
588 <h2><A name="as_lock">Using <code>shared_ptr</code> as a CopyConstructible mutex lock</A></h2>
589 <p>Sometimes it's necessary to return a mutex lock from a function, and a
590 noncopyable lock cannot be returned by value. It is possible to use <code>shared_ptr</code>
591 as a mutex lock:</p>
592 <pre>class mutex
593{
594public:
595
596 void lock();
597 void unlock();
598};
599
600shared_ptr&lt;mutex&gt; lock(mutex &amp; m)
601{
602 m.lock();
603 return shared_ptr&lt;mutex&gt;(&amp;m, mem_fn(&amp;mutex::unlock));
604}
605</pre>
606 <p>Better yet, the <code>shared_ptr</code> instance acting as a lock can be
607 encapsulated in a dedicated <code>shared_lock</code> class:</p>
608 <pre>class shared_lock
609{
610private:
611
612 shared_ptr&lt;void&gt; pv;
613
614public:
615
616 template&lt;class Mutex&gt; explicit shared_lock(Mutex &amp; m): pv((m.lock(), &amp;m), mem_fn(&amp;Mutex::unlock)) {}
617};
618</pre>
619 <p><code>shared_lock</code> can now be used as:</p>
620 <pre> shared_lock lock(m);
621</pre>
622 <p>Note that <code>shared_lock</code> is not templated on the mutex type, thanks to <code>
623 shared_ptr&lt;void&gt;</code>'s ability to hide type information.</p>
624 <h2><A name="wrapper">Using <code>shared_ptr</code> to wrap member function calls</A></h2>
625 <p><code>shared_ptr</code> implements the ownership semantics required from the <code>Wrap</code>/<code>CallProxy</code>
626 scheme described in Bjarne Stroustrup's article "Wrapping C++ Member Function
627 Calls" (available online at <A href="http://www.stroustrup.com/wrapper.pdf">http://www.stroustrup.com/wrapper.pdf</A>).
628 An implementation is given below:</p>
629 <pre>template&lt;class T&gt; class pointer
630{
631private:
632
633 T * p_;
634
635public:
636
637 explicit pointer(T * p): p_(p)
638 {
639 }
640
641 shared_ptr&lt;T&gt; operator-&gt;() const
642 {
643 p_-&gt;prefix();
644 return shared_ptr&lt;T&gt;(p_, <A href="../bind/mem_fn.html" >mem_fn</A>(&amp;T::suffix));
645 }
646};
647
648class X
649{
650private:
651
652 void prefix();
653 void suffix();
654 friend class pointer&lt;X&gt;;
655
656public:
657
658 void f();
659 void g();
660};
661
662int main()
663{
664 X x;
665
666 pointer&lt;X&gt; px(&amp;x);
667
668 px-&gt;f();
669 px-&gt;g();
670}
671</pre>
672 <h2><A name="delayed">Delayed deallocation</A></h2>
673 <p>In some situations, a single <code>px.reset()</code> can trigger an expensive
674 deallocation in a performance-critical region:</p>
675 <pre>class X; // ~X is expensive
676
677class Y
678{
679 shared_ptr&lt;X&gt; px;
680
681public:
682
683 void f()
684 {
685 px.reset();
686 }
687};
688</pre>
689 <p>The solution is to postpone the potential deallocation by moving <code>px</code>
690 to a dedicated free list that can be periodically emptied when performance and
691 response times are not an issue:</p>
692 <pre>vector&lt; shared_ptr&lt;void&gt; &gt; free_list;
693
694class Y
695{
696 shared_ptr&lt;X&gt; px;
697
698public:
699
700 void f()
701 {
702 free_list.push_back(px);
703 px.reset();
704 }
705};
706
707// periodically invoke free_list.clear() when convenient
708</pre>
709 <p>Another variation is to move the free list logic to the construction point by
710 using a delayed deleter:</p>
711 <pre>struct delayed_deleter
712{
713 template&lt;class T&gt; void operator()(T * p)
714 {
715 try
716 {
717 shared_ptr&lt;void&gt; pv(p);
718 free_list.push_back(pv);
719 }
720 catch(...)
721 {
722 }
723 }
724};
725</pre>
726 <h2><A name="weak_without_shared">Weak pointers to objects not managed by a <code>shared_ptr</code></A></h2>
727 <p>Make the object hold a <code>shared_ptr</code> to itself, using a <code>null_deleter</code>:</p>
728 <pre>class X
729{
730private:
731
732 shared_ptr&lt;X&gt; this_;
733 int i_;
734
735public:
736
737 explicit X(int i): this_(this, null_deleter()), i_(i)
738 {
739 }
740
741 // repeat in all constructors (including the copy constructor!)
742
743 X(X const &amp; rhs): this_(this, null_deleter()), i_(rhs.i_)
744 {
745 }
746
747 // do not forget to not assign this_ in the copy assignment
748
749 X &amp; operator=(X const &amp; rhs)
750 {
751 i_ = rhs.i_;
752 }
753
754 weak_ptr&lt;X&gt; get_weak_ptr() const { return this_; }
755};
756</pre>
757 <p>When the object's lifetime ends, <code>X::this_</code> will be destroyed, and
758 all weak pointers will automatically expire.</p>
759 <hr>
760 <p>$Date$</p>
761 <p><small>Copyright &copy; 2003 Peter Dimov. Distributed under the Boost Software License, Version
762 1.0. See accompanying file <A href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</A> or
763 copy at <A href="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</A>.</small></p>
764 </body>
765</html>