Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/libs/smart_ptr/sp_techniques.html @ 12

Last change on this file since 12 was 12, checked in by landauf, 17 years ago

added boost

File size: 25.2 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><IMG height="86" alt="boost.png (6897 bytes)" src="../../boost.png" width="277" align="middle">Smart
9                        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                <h2><A name="handle">Using <code>shared_ptr</code> as a smart counted handle</A></h2>
523                <p>Some library interfaces use opaque handles, a variation of the <A href="#incomplete">
524                                incomplete class technique</A> described above. An example:</p>
525                <pre>typedef void * HANDLE;
526HANDLE CreateProcess();
527void CloseHandle(HANDLE);
528</pre>
529                <p>Instead of a raw pointer, it is possible to use <code>shared_ptr</code> as the
530                        handle and get reference counting and automatic resource management for free:</p>
531                <pre>typedef shared_ptr&lt;void&gt; handle;
532
533handle createProcess()
534{
535    shared_ptr&lt;void&gt; pv(CreateProcess(), CloseHandle);
536    return pv;
537}
538</pre>
539                <h2><A name="on_block_exit">Using <code>shared_ptr</code> to execute code on block exit</A></h2>
540                <p><code>shared_ptr&lt;void&gt;</code> can automatically execute cleanup code when
541                        control leaves a scope.</p>
542                <UL>
543                        <LI>
544                                Executing <code>f(p)</code>, where <code>p</code> is a pointer:</LI></UL>
545                <pre>    shared_ptr&lt;void&gt; guard(p, f);
546</pre>
547                <UL>
548                        <LI>
549                                Executing arbitrary code: <code>f(x, y)</code>:</LI></UL>
550                <pre>    shared_ptr&lt;void&gt; guard(static_cast&lt;void*&gt;(0), <A href="../bind/bind.html" >bind</A>(f, x, y));
551</pre>
552                <P>For a more thorough treatment, see the article "Simplify Your Exception-Safe
553                        Code" by Andrei Alexandrescu and Petru Marginean, available online at <A href="http://www.cuj.com/experts/1812/alexandr.htm?topic=experts">
554                                http://www.cuj.com/experts/1812/alexandr.htm?topic=experts</A>.</P>
555                <h2><A name="pvoid">Using <code>shared_ptr&lt;void&gt;</code> to hold an arbitrary
556                                object</A></h2>
557                <p><code>shared_ptr&lt;void&gt;</code> can act as a generic object pointer similar
558                        to <code>void*</code>. When a <code>shared_ptr&lt;void&gt;</code> instance
559                        constructed as:</p>
560                <pre>    shared_ptr&lt;void&gt; pv(new X);
561</pre>
562                <p>is destroyed, it will correctly dispose of the <code>X</code> object by
563                        executing <code>~X</code>.</p>
564                <p>This propery can be used in much the same manner as a raw <code>void*</code> is
565                        used to temporarily strip type information from an object pointer. A <code>shared_ptr&lt;void&gt;</code>
566                        can later be cast back to the correct type by using <code><A href="shared_ptr.htm#static_pointer_cast">
567                                        static_pointer_cast</A></code>.</p>
568                <h2><A name="extra_data">Associating arbitrary data with heterogeneous <code>shared_ptr</code>
569                                instances</A></h2>
570                <p><code>shared_ptr</code> and <code>weak_ptr</code> support <code>operator&lt;</code>
571                        comparisons required by standard associative containers such as <code>std::map</code>.
572                        This can be used to non-intrusively associate arbitrary data with objects
573                        managed by <code>shared_ptr</code>:</p>
574                <pre>typedef int Data;
575
576std::map&lt; shared_ptr&lt;void&gt;, Data &gt; userData;
577// or std::map&lt; weak_ptr&lt;void&gt;, Data &gt; userData; to not affect the lifetime
578
579shared_ptr&lt;X&gt; px(new X);
580shared_ptr&lt;int&gt; pi(new int(3));
581
582userData[px] = 42;
583userData[pi] = 91;
584</pre>
585                <h2><A name="as_lock">Using <code>shared_ptr</code> as a CopyConstructible mutex lock</A></h2>
586                <p>Sometimes it's necessary to return a mutex lock from a function, and a
587                        noncopyable lock cannot be returned by value. It is possible to use <code>shared_ptr</code>
588                        as a mutex lock:</p>
589                <pre>class mutex
590{
591public:
592
593    void lock();
594    void unlock();
595};
596
597shared_ptr&lt;mutex&gt; lock(mutex &amp; m)
598{
599    m.lock();
600    return shared_ptr&lt;mutex&gt;(&amp;m, mem_fn(&amp;mutex::unlock));
601}
602</pre>
603                <p>Better yet, the <code>shared_ptr</code> instance acting as a lock can be
604                        encapsulated in a dedicated <code>shared_lock</code> class:</p>
605                <pre>class shared_lock
606{
607private:
608
609    shared_ptr&lt;void&gt; pv;
610
611public:
612
613    template&lt;class Mutex&gt; explicit shared_lock(Mutex &amp; m): pv((m.lock(), &amp;m), mem_fn(&amp;Mutex::unlock)) {}
614};
615</pre>
616                <p><code>shared_lock</code> can now be used as:</p>
617                <pre>    shared_lock lock(m);
618</pre>
619                <p>Note that <code>shared_lock</code> is not templated on the mutex type, thanks to <code>
620                                shared_ptr&lt;void&gt;</code>'s ability to hide type information.</p>
621                <h2><A name="wrapper">Using <code>shared_ptr</code> to wrap member function calls</A></h2>
622                <p><code>shared_ptr</code> implements the ownership semantics required from the <code>Wrap</code>/<code>CallProxy</code>
623                        scheme described in Bjarne Stroustrup's article "Wrapping C++ Member Function
624                        Calls" (available online at <A href="http://www.research.att.com/~bs/wrapper.pdf">http://www.research.att.com/~bs/wrapper.pdf</A>).
625                        An implementation is given below:</p>
626                <pre>template&lt;class T&gt; class pointer
627{
628private:
629
630    T * p_;
631
632public:
633
634    explicit pointer(T * p): p_(p)
635    {
636    }
637
638    shared_ptr&lt;T&gt; operator-&gt;() const
639    {
640        p_-&gt;prefix();
641        return shared_ptr&lt;T&gt;(p_, <A href="../bind/mem_fn.html" >mem_fn</A>(&amp;T::suffix));
642    }
643};
644
645class X
646{
647private:
648
649    void prefix();
650    void suffix();
651    friend class pointer&lt;X&gt;;
652   
653public:
654
655    void f();
656    void g();
657};
658
659int main()
660{
661    X x;
662
663    pointer&lt;X&gt; px(&amp;x);
664
665    px-&gt;f();
666    px-&gt;g();
667}
668</pre>
669                <h2><A name="delayed">Delayed deallocation</A></h2>
670                <p>In some situations, a single <code>px.reset()</code> can trigger an expensive
671                        deallocation in a performance-critical region:</p>
672                <pre>class X; // ~X is expensive
673
674class Y
675{
676    shared_ptr&lt;X&gt; px;
677
678public:
679
680    void f()
681    {
682        px.reset();
683    }
684};
685</pre>
686                <p>The solution is to postpone the potential deallocation by moving <code>px</code> 
687                        to a dedicated free list that can be periodically emptied when performance and
688                        response times are not an issue:</p>
689                <pre>vector&lt; shared_ptr&lt;void&gt; &gt; free_list;
690
691class Y
692{
693    shared_ptr&lt;X&gt; px;
694
695public:
696
697    void f()
698    {
699        free_list.push_back(px);
700        px.reset();
701    }
702};
703
704// periodically invoke free_list.clear() when convenient
705</pre>
706                <p>Another variation is to move the free list logic to the construction point by
707                        using a delayed deleter:</p>
708                <pre>struct delayed_deleter
709{
710    template&lt;class T&gt; void operator()(T * p)
711    {
712        try
713        {
714            shared_ptr&lt;void&gt; pv(p);
715            free_list.push_back(pv);
716        }
717        catch(...)
718        {
719        }
720    }
721};
722</pre>
723                <h2><A name="weak_without_shared">Weak pointers to objects not managed by a <code>shared_ptr</code></A></h2>
724                <p>Make the object hold a <code>shared_ptr</code> to itself, using a <code>null_deleter</code>:</p>
725                <pre>class X
726{
727private:
728
729    shared_ptr&lt;X&gt; this_;
730    int i_;
731
732public:
733
734    explicit X(int i): this_(this, null_deleter()), i_(i)
735    {
736    }
737
738    // repeat in all constructors (including the copy constructor!)
739
740    X(X const &amp; rhs): this_(this, null_deleter()), i_(rhs.i_)
741    {
742    }
743
744    // do not forget to not assign this_ in the copy assignment
745
746    X &amp; operator=(X const &amp; rhs)
747    {
748            i_ = rhs.i_;
749    }
750
751    weak_ptr&lt;X&gt; get_weak_ptr() const { return this_; }
752};
753</pre>
754                <p>When the object's lifetime ends, <code>X::this_</code> will be destroyed, and
755                        all weak pointers will automatically expire.</p>
756                <hr>
757                <p>$Date: 2005/01/13 13:45:59 $</p>
758                <p><small>Copyright © 2003 Peter Dimov. Permission to copy, use, modify, sell and
759                                distribute this document is granted provided this copyright notice appears in
760                                all copies. This document is provided "as is" without express or implied
761                                warranty, and with no claim as to its suitability for any purpose.</small></p>
762        </body>
763</html>
Note: See TracBrowser for help on using the repository browser.