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