Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/smart_ptr/sp_techniques.html @ 45

Last change on this file since 45 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 25.5 KB
Line 
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">
8                <h1><A href="../../index.htm"><IMG height="86" alt="boost.png (6897 bytes)" src="../../boost.png" width="277" align="middle"
9                                        border="0"></A>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.research.att.com/~bs/wrapper.pdf">http://www.research.att.com/~bs/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: 2006/11/09 20:22:24 $</p>
761                <p><small>Copyright © 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>
Note: See TracBrowser for help on using the repository browser.