forked from boostorg/smart_ptr
Some prose added.
[SVN r17331]
This commit is contained in:
@ -15,21 +15,23 @@
|
||||
<A href="#array">Using a <code>shared_ptr</code> to hold a pointer to an array</A><br>
|
||||
<A href="#encapsulation">Encapsulating allocation details, wrapping factory
|
||||
functions</A><br>
|
||||
<A href="#static">Using a <code>shared_ptr</code> to hold a pointer to a statically allocated
|
||||
object</A><br>
|
||||
<A href="#static">Using a <code>shared_ptr</code> to hold a pointer to a statically
|
||||
allocated object</A><br>
|
||||
<A href="#com">Using a <code>shared_ptr</code> to hold a pointer to a COM object</A><br>
|
||||
<A href="#intrusive">Using a <code>shared_ptr</code> to hold a pointer to an object with an
|
||||
embedded reference count</A><br>
|
||||
<A href="#another_sp">Using a <code>shared_ptr</code> to hold another shared ownership smart
|
||||
pointer</A><br>
|
||||
<A href="#intrusive">Using a <code>shared_ptr</code> to hold a pointer to an object
|
||||
with an embedded reference count</A><br>
|
||||
<A href="#another_sp">Using a <code>shared_ptr</code> to hold another shared
|
||||
ownership smart pointer</A><br>
|
||||
<A href="#from_raw">Obtaining a <code>shared_ptr</code> from a raw pointer</A><br>
|
||||
<A href="#in_constructor">Obtaining a <code>shared_ptr</code> (<code>weak_ptr</code>) to <code>this</code> in a
|
||||
constructor</A><br>
|
||||
<A href="#in_constructor">Obtaining a <code>shared_ptr</code> (<code>weak_ptr</code>)
|
||||
to <code>this</code> in a constructor</A><br>
|
||||
<A href="#from_this">Obtaining a <code>shared_ptr</code> to <code>this</code></A><br>
|
||||
<A href="#handle">Using <code>shared_ptr</code> as a smart counted handle</A><br>
|
||||
<A href="#on_block_exit">Using <code>shared_ptr</code> to execute code on block exit</A><br>
|
||||
<A href="#pvoid">Using <code>shared_ptr<void></code> to hold an arbitrary object</A><br>
|
||||
<A href="#extra_data">Associating arbitrary data with heterogeneous <code>shared_ptr</code>
|
||||
<A href="#on_block_exit">Using <code>shared_ptr</code> to execute code on block
|
||||
exit</A><br>
|
||||
<A href="#pvoid">Using <code>shared_ptr<void></code> to hold an arbitrary
|
||||
object</A><br>
|
||||
<A href="#extra_data">Associating arbitrary data with heterogeneous <code>shared_ptr</code>
|
||||
instances</A><br>
|
||||
<A href="#pre_destructor">Post-constructors and pre-destructors</A><br>
|
||||
<A href="#as_lock">Using <code>shared_ptr</code> as a CopyConstructible mutex lock</A><br>
|
||||
@ -38,27 +40,32 @@
|
||||
<A href="#weak_without_shared">Weak pointers to objects not managed by a <code>shared_ptr</code></A><br>
|
||||
</p>
|
||||
<h2><A name="incomplete">Using incomplete classes for implementation hiding</A></h2>
|
||||
<p>[Old, proven technique; can be used in C]</p>
|
||||
<pre>
|
||||
<p>A 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:</p>
|
||||
<pre>
|
||||
class FILE;
|
||||
|
||||
FILE * fopen(char const * name, char const * mode);
|
||||
void fread(FILE * f, void * data, size_t size);
|
||||
void fclose(FILE * f);
|
||||
</pre>
|
||||
<p>[Compare with]</p>
|
||||
<pre>
|
||||
<p>It is possible to express the above interface using <code>shared_ptr</code>,
|
||||
eliminating the need to manually call <code>fclose</code>:</p>
|
||||
<pre>
|
||||
class FILE;
|
||||
|
||||
shared_ptr<FILE> fopen(char const * name, char const * mode);
|
||||
void fread(shared_ptr<FILE> f, void * data, size_t size);
|
||||
</pre>
|
||||
<p>Note that there is no <code>fclose</code> function; <code>shared_ptr</code>'s ability to execute a custom deleter makes it unnecessary.</p>
|
||||
|
||||
<p>[<code>shared_ptr<X></code> can be copied and destroyed when <code>X</code> is incomplete.]</p>
|
||||
<p>This technique relies on <code>shared_ptr</code>'s ability to execute a custom
|
||||
deleter, eliminating the explicit call to <code>fclose</code>, and on the fact
|
||||
that <code>shared_ptr<X></code> can be copied and destroyed when <code>X</code>
|
||||
is incomplete.</p>
|
||||
<h2><A name="pimpl">The "Pimpl" idiom</A></h2>
|
||||
<p>[...]</p>
|
||||
<pre>
|
||||
<p>A C++ 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. <code>shared_ptr</code> can be used to implement a "Pimpl":</p>
|
||||
<pre>
|
||||
// file.hpp:
|
||||
|
||||
class file
|
||||
@ -77,7 +84,7 @@ public:
|
||||
void read(void * data, size_t size);
|
||||
};
|
||||
</pre>
|
||||
<pre>
|
||||
<pre>
|
||||
// file.cpp:
|
||||
|
||||
#include "file.hpp"
|
||||
@ -107,10 +114,17 @@ void file::read(void * data, size_t size)
|
||||
pimpl_->read(data, size);
|
||||
}
|
||||
</pre>
|
||||
<p>[<code>file</code> is CopyConstructible and Assignable.]</p>
|
||||
<p>The key thing to note here is that the compiler-generated copy constructor,
|
||||
assignment operator, and destructor all have a sensible meaning. As a result, <code>
|
||||
file</code> is <code>CopyConstructible</code> and <code>Assignable</code>,
|
||||
allowing its use in standard containers.</p>
|
||||
<h2><A name="abstract">Using abstract classes for implementation hiding</A></h2>
|
||||
<p>[Interface based programming]</p>
|
||||
<pre>
|
||||
<p>Another widely used C++ idiom for separating inteface and implementation is to
|
||||
use abstract base classes and factory functions. The abstract classes are
|
||||
sometimes called "interfaces" and the pattern is known as "interface-based
|
||||
programming". Again, <code>shared_ptr</code> can be used as the return type of
|
||||
the factory functions:</p>
|
||||
<pre>
|
||||
// X.hpp:
|
||||
|
||||
class X
|
||||
@ -127,7 +141,7 @@ protected:
|
||||
|
||||
shared_ptr<X> createX();
|
||||
</pre>
|
||||
<pre>
|
||||
<pre>
|
||||
-- X.cpp:
|
||||
|
||||
class X_impl: public X
|
||||
@ -156,11 +170,18 @@ shared_ptr<X> createX()
|
||||
return px;
|
||||
}
|
||||
</pre>
|
||||
<p>[Note protected and nonvirtual destructor; client cannot delete <code>X</code>; <code>shared_ptr</code> correctly calls <code>~X_impl</code> even when nonvirtual.]</p>
|
||||
<p>A 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. Note the protected and nonvirtual destructor in the example
|
||||
above. The client code cannot, and does not need to, delete a pointer to <code>X</code>;
|
||||
the <code>shared_ptr<X></code> instance returned from <code>createX</code>
|
||||
will correctly call <code>~X_impl</code>.</p>
|
||||
<h2><A name="preventing_delete">Preventing <code>delete px.get()</code></A></h2>
|
||||
<p>[Alternative 1, use the above.]</p>
|
||||
<p>[Alternative 2, use a private deleter:]</p>
|
||||
<pre>
|
||||
<p>It is often desirable to prevent client code from deleting a pointer that is
|
||||
being managed by <code>shared_ptr</code>. The previous technique showed one
|
||||
possible approach, using a protected destructor. Another alternative is to use
|
||||
a private deleter:</p>
|
||||
<pre>
|
||||
class X
|
||||
{
|
||||
private:
|
||||
@ -187,34 +208,51 @@ public:
|
||||
};
|
||||
</pre>
|
||||
<h2><A name="array">Using a <code>shared_ptr</code> to hold a pointer to an array</A></h2>
|
||||
<p>[...]</p>
|
||||
<pre>
|
||||
shared_ptr<X> px(new X[1], checked_array_deleter<X>());
|
||||
<p>A <code>shared_ptr</code> can be used to hold a pointer to an array allocated
|
||||
with <code>new[]</code>:</p>
|
||||
<pre>
|
||||
shared_ptr<X> px(new X[1], <A href="../utility/checked_delete.html">checked_array_deleter</A><X>());
|
||||
</pre>
|
||||
<p>[<code>shared_array</code> is preferable, has a better interface; <code>shared_ptr</code> has *, ->, derived to base conversions.]</p>
|
||||
<p>Note, however, that <code><A href="shared_array.htm">shared_array</A></code> is
|
||||
often preferable, if this is an option. It has an array-specific interface,
|
||||
without <code>operator*</code> and <code>operator-></code>, and does not
|
||||
allow pointer conversions.</p>
|
||||
<h2><A name="encapsulation">Encapsulating allocation details, wrapping factory
|
||||
functions</A></h2>
|
||||
<p>[Existing interface, possibly allocates <code>X</code> from its own heap, <code>~X</code> is private, or <code>X</code> is incomplete.]</p>
|
||||
<pre>
|
||||
<p><code>shared_ptr</code> can be used in creating C++ wrappers over existing C
|
||||
style library interfaces that return raw pointers from their factory functions
|
||||
to encapsulate allocation details. As an example, consider this interface,
|
||||
where <code>CreateX</code> might allocate <code>X</code> from its own private
|
||||
heap, <code>~X</code> may be inaccessible, or <code>X</code> may be incomplete:</p>
|
||||
<pre>
|
||||
X * CreateX();
|
||||
void DestroyX(X *);
|
||||
</pre>
|
||||
<p>[Wrapper:]</p>
|
||||
<pre>
|
||||
<p>The only way to reliably destroy a pointer returned by <code>CreateX</code> is
|
||||
to call <code>DestroyX</code>.</p>
|
||||
<P>Here is how a <code>shared_ptr</code>-based wrapper may look like:</P>
|
||||
<pre>
|
||||
shared_ptr<X> createX()
|
||||
{
|
||||
shared_ptr<X> px(CreateX(), DestroyX);
|
||||
return px;
|
||||
}
|
||||
</pre>
|
||||
<p>[Client remains blissfully oblivious of allocation details; doesn't need to remember to call <code>destroyX</code>.]</p>
|
||||
<h2><A name="static">Using a <code>shared_ptr</code> to hold a pointer to a statically allocated
|
||||
object</A></h2>
|
||||
<p>[...]</p>
|
||||
<pre>
|
||||
<p>Client code that calls <code>createX</code> still does not need to know how the
|
||||
object has been allocated, but now the destruction is automatic.</p>
|
||||
<h2><A name="static">Using a <code>shared_ptr</code> to hold a pointer to a statically
|
||||
allocated object</A></h2>
|
||||
<p>Sometimes it is desirable to create a <code>shared_ptr</code> to an already
|
||||
existing object, so that the <code>shared_ptr</code> does not attempt to
|
||||
destroy the object when there are no more references left. As an example, the
|
||||
factory function:</p>
|
||||
<pre>
|
||||
shared_ptr<X> createX();
|
||||
</pre>
|
||||
<p>[Sometimes needs to return a pointer to a statically allocated <code>X</code> instance.]</p>
|
||||
<pre>
|
||||
<p>in certain situations may need to return a pointer to a statically allocated <code>X</code>
|
||||
instance.</p>
|
||||
<P>The solution is to use a custom deleter that does nothing:</P>
|
||||
<pre>
|
||||
struct null_deleter
|
||||
{
|
||||
void operator()(void const *) const
|
||||
@ -230,22 +268,31 @@ shared_ptr<X> createX()
|
||||
return px;
|
||||
}
|
||||
</pre>
|
||||
<p>[The same technique works for any object known to outlive the pointer.]</p>
|
||||
<p>The same technique works for any object known to outlive the pointer.</p>
|
||||
<h2><A name="com">Using a <code>shared_ptr</code> to hold a pointer to a COM Object</A></h2>
|
||||
<p>[COM objects have an embedded reference count, <code>AddRef()</code> and <code>Release()</code>, <code>Release()</code> self-destroys when reference count drops to zero.]</p>
|
||||
<pre>
|
||||
<p>Background: COM objects have an embedded reference count and two member
|
||||
functions that manipulate it. <code>AddRef()</code> increments the count. <code>Release()</code>
|
||||
decrements the count and destroys itself when the count drops to zero.</p>
|
||||
<P>It is possible to hold a pointer to a COM object in a <code>shared_ptr</code>:</P>
|
||||
<pre>
|
||||
shared_ptr<IWhatever> make_shared_from_COM(IWhatever * p)
|
||||
{
|
||||
p->AddRef();
|
||||
shared_ptr<IWhatever> pw(p, mem_fn(&IWhatever::Release));
|
||||
shared_ptr<IWhatever> pw(p, <A href="../bind/mem_fn.html">mem_fn</A>(&IWhatever::Release));
|
||||
return pw;
|
||||
}
|
||||
</pre>
|
||||
<p>[All pw copies will share a single reference.]</p>
|
||||
<h2><A name="intrusive">Using a <code>shared_ptr</code> to hold a pointer to an object with an
|
||||
embedded reference count</A></h2>
|
||||
<p>[A generalization of the above. Example assumes <code>intrusive_ptr</code>-compatible object.]</p>
|
||||
<pre>
|
||||
<p>Note, however, that <code>shared_ptr</code> copies created from <code>pw</code> will
|
||||
not "register" in the embedded count of the COM object; they will share the
|
||||
single reference created in <code>make_shared_from_COM</code>. Weak pointers
|
||||
created from <code>pw</code> will be invalidated when the last <code>shared_ptr</code>
|
||||
is destroyed, regardless of whether the COM object itself is still alive.</p>
|
||||
<h2><A name="intrusive">Using a <code>shared_ptr</code> to hold a pointer to an object
|
||||
with an embedded reference count</A></h2>
|
||||
<p>This is a generalization of the above technique. The example assumes that the
|
||||
object implements the two functions required by <code><A href="intrusive_ptr.html">intrusive_ptr</A></code>,
|
||||
<code>intrusive_ptr_add_ref</code> and <code>intrusive_ptr_release</code>:</p>
|
||||
<pre>
|
||||
template<class T> struct intrusive_deleter
|
||||
{
|
||||
void operator()(T * p)
|
||||
@ -261,11 +308,16 @@ shared_ptr<X> make_shared_from_intrusive(X * p)
|
||||
return px;
|
||||
}
|
||||
</pre>
|
||||
<h2><A name="another_sp">Using a <code>shared_ptr</code> to hold another shared ownership smart
|
||||
pointer</A></h2>
|
||||
<p>[...]</p>
|
||||
<pre>
|
||||
template<class P> class smart_pointer_deleter
|
||||
<h2><A name="another_sp">Using a <code>shared_ptr</code> to hold another shared
|
||||
ownership smart pointer</A></h2>
|
||||
<p>One of the design goals of <code>shared_ptr</code> is to be used in library
|
||||
interfaces. It is possible to encounter a situation where a library takes a <code>shared_ptr</code>
|
||||
argument, but the object at hand is being managed by a different reference
|
||||
counted or linked smart pointer.</p>
|
||||
<P>It is possible to exploit <code>shared_ptr</code>'s custom deleter feature to
|
||||
wrap this existing smart pointer behind a <code>shared_ptr</code> facade:</P>
|
||||
<pre>
|
||||
template<class P> struct smart_pointer_deleter
|
||||
{
|
||||
private:
|
||||
|
||||
@ -281,40 +333,77 @@ public:
|
||||
{
|
||||
p_.reset();
|
||||
}
|
||||
|
||||
P const & get() const
|
||||
{
|
||||
return p_;
|
||||
}
|
||||
};
|
||||
|
||||
shared_ptr<X> make_shared_from_another(another_ptr<X> qx)
|
||||
{
|
||||
shared_ptr<X> px(qx.get(), smart_pointer_deleter< another_ptr<X> >(qx));
|
||||
shared_ptr<X> px(qx.get(), smart_pointer_deleter< another_ptr<X> >(qx));
|
||||
return px;
|
||||
}
|
||||
</pre>
|
||||
<p>[If <code>p_.reset()</code> can throw - wrap in <code>try {} catch(...) {}</code> block, will release <code>p_</code> when all weak pointers are eliminated.]</p>
|
||||
<p>One subtle point is that deleters are not allowed to throw exceptions, and the
|
||||
above example as written assumes that <code>p_.reset()</code> doesn't throw. If
|
||||
this is not the case, <code>p_.reset()</code> should be wrapped in a <code>try {}
|
||||
catch(...) {}</code> block that ignores exceptions. In the (usually
|
||||
unlikely) event when an exception is thrown and ignored, <code>p_</code> will
|
||||
be released when the lifetime of the deleter ends. This happens when all
|
||||
references, including weak pointers, are destroyed or reset.</p>
|
||||
<P>Another twist is that it is possible, given the above <code>shared_ptr</code> instance,
|
||||
to recover the original smart pointer, using <code><A href="shared_ptr.htm#get_deleter">
|
||||
get_deleter</A></code>:</P>
|
||||
<pre>
|
||||
void extract_another_from_shared(shared_ptr<X> px)
|
||||
{
|
||||
typedef smart_pointer_deleter< another_ptr<X> > deleter;
|
||||
|
||||
if(deleter const * pd = get_deleter<deleter>(px))
|
||||
{
|
||||
another_ptr<X> qx = pd->get();
|
||||
}
|
||||
else
|
||||
{
|
||||
// not one of ours
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
<h2><A name="from_raw">Obtaining a <code>shared_ptr</code> from a raw pointer</A></h2>
|
||||
<p>[...]</p>
|
||||
<pre>
|
||||
<p>Sometimes it is necessary to obtain a <code>shared_ptr</code> given a raw
|
||||
pointer to an object that is already managed by another <code>shared_ptr</code>
|
||||
instance. Example:</p>
|
||||
<pre>
|
||||
void f(X * p)
|
||||
{
|
||||
shared_ptr<X> px(<i>???</i>);
|
||||
}
|
||||
</pre>
|
||||
<p>[Not possible in general, either switch to]</p>
|
||||
<pre>
|
||||
<p>Inside <code>f</code>, we'd like to create a <code>shared_ptr</code> to <code>*p</code>.</p>
|
||||
<P>In the general case, this problem has no solution. One approach is to modify <code>f</code>
|
||||
to take a <code>shared_ptr</code>, if possible:</P>
|
||||
<pre>
|
||||
void f(shared_ptr<X> px);
|
||||
</pre>
|
||||
<p>[This transformation can be used for nonvirtual member functions, too; before:]</p>
|
||||
<pre>
|
||||
<p>The same transformation can be used for nonvirtual member functions, to convert
|
||||
the implicit <code>this</code>:</p>
|
||||
<pre>
|
||||
void X::f(int m);
|
||||
</pre>
|
||||
<p>[after]</p>
|
||||
<pre>
|
||||
<p>would become a free function with a <code>shared_ptr</code> first argument:</p>
|
||||
<pre>
|
||||
void f(shared_ptr<X> this_, int m);
|
||||
</pre>
|
||||
<p>[If <code>f</code> cannot be changed, use knowledge about <code>p</code>'s lifetime and allocation details and apply one of the above.]</p>
|
||||
<h2><A name="in_constructor">Obtaining a <code>shared_ptr</code> (<code>weak_ptr</code>) to <code>this</code> in a
|
||||
constructor</A></h2>
|
||||
<p>[...]</p>
|
||||
<pre>
|
||||
<p>If <code>f</code> cannot be changed, but <code>X</code> has an embedded
|
||||
reference count, use <code><A href="#intrusive">make_shared_from_intrusive</A></code>
|
||||
described above. Or, if it's known that the <code>shared_ptr</code> created in <code>
|
||||
f</code> will never outlive the object, use <A href="#static">a null deleter</A>.</p>
|
||||
<h2><A name="in_constructor">Obtaining a <code>shared_ptr</code> (<code>weak_ptr</code>)
|
||||
to <code>this</code> in a constructor</A></h2>
|
||||
<p>[...]</p>
|
||||
<pre>
|
||||
class X
|
||||
{
|
||||
public:
|
||||
@ -325,9 +414,11 @@ public:
|
||||
}
|
||||
};
|
||||
</pre>
|
||||
<p>[Not possible in general. If <code>X</code> can have automatic or static storage, and <code>this_</code> doesn't need to keep the object alive,
|
||||
use a <code>null_deleter</code>. If <code>X</code> is supposed to always live on the heap, and be managed by a <code>shared_ptr</code>, use:]</p>
|
||||
<pre>
|
||||
<p>[Not possible in general. If <code>X</code> can have automatic or static
|
||||
storage, and <code>this_</code> doesn't need to keep the object alive, use a <code>null_deleter</code>.
|
||||
If <code>X</code> is supposed to always live on the heap, and be managed by a <code>
|
||||
shared_ptr</code>, use:]</p>
|
||||
<pre>
|
||||
class X
|
||||
{
|
||||
private:
|
||||
@ -345,9 +436,10 @@ public:
|
||||
};
|
||||
</pre>
|
||||
<h2><A name="from_this">Obtaining a <code>shared_ptr</code> to <code>this</code></A></h2>
|
||||
<p>[Sometimes it is needed to obtain a shared_ptr from this in a virtual member function.]</p>
|
||||
<p>[The transformations from above cannot be applied.]</p>
|
||||
<pre>
|
||||
<p>[Sometimes it is needed to obtain a shared_ptr from this in a virtual member
|
||||
function.]</p>
|
||||
<p>[The transformations from above cannot be applied.]</p>
|
||||
<pre>
|
||||
class X
|
||||
{
|
||||
public:
|
||||
@ -387,8 +479,8 @@ public:
|
||||
}
|
||||
};
|
||||
</pre>
|
||||
<p>[Solution:]</p>
|
||||
<pre>
|
||||
<p>[Solution:]</p>
|
||||
<pre>
|
||||
class impl: public X, public Y
|
||||
{
|
||||
private:
|
||||
@ -418,16 +510,16 @@ public:
|
||||
}
|
||||
};
|
||||
</pre>
|
||||
<p>[Future support planned, <code>impl: public enable_shared_from_this<impl></code>.]</p>
|
||||
<p>[Future support planned, <code>impl: public enable_shared_from_this<impl></code>.]</p>
|
||||
<h2><A name="handle">Using <code>shared_ptr</code> as a smart counted handle</A></h2>
|
||||
<p>[Win32 API allusion]</p>
|
||||
<pre>
|
||||
<p>[Win32 API allusion]</p>
|
||||
<pre>
|
||||
typedef void * HANDLE;
|
||||
HANDLE CreateProcess();
|
||||
void CloseHandle(HANDLE);
|
||||
</pre>
|
||||
<p>[Quick wrapper]</p>
|
||||
<pre>
|
||||
<p>[Quick wrapper]</p>
|
||||
<pre>
|
||||
typedef shared_ptr<void> handle;
|
||||
|
||||
handle createProcess()
|
||||
@ -436,8 +528,8 @@ handle createProcess()
|
||||
return pv;
|
||||
}
|
||||
</pre>
|
||||
<p>[Better, typesafe:]</p>
|
||||
<pre>
|
||||
<p>[Better, typesafe:]</p>
|
||||
<pre>
|
||||
class handle
|
||||
{
|
||||
private:
|
||||
@ -451,25 +543,27 @@ public:
|
||||
};
|
||||
</pre>
|
||||
<h2><A name="on_block_exit">Using <code>shared_ptr</code> to execute code on block exit</A></h2>
|
||||
<p>[1. Executing <code>f(p)</code>, where <code>p</code> is a pointer:]</p>
|
||||
<pre>
|
||||
<p>[1. Executing <code>f(p)</code>, where <code>p</code> is a pointer:]</p>
|
||||
<pre>
|
||||
shared_ptr<void> guard(p, f);
|
||||
</pre>
|
||||
<p>[2. Executing arbitrary code: <code>f(x, y)</code>:]</p>
|
||||
<pre>
|
||||
<p>[2. Executing arbitrary code: <code>f(x, y)</code>:]</p>
|
||||
<pre>
|
||||
shared_ptr<void> guard(static_cast<void*>(0), bind(f, x, y));
|
||||
</pre>
|
||||
<h2><A name="pvoid">Using <code>shared_ptr<void></code> to hold an arbitrary object</A></h2>
|
||||
<p>[...]</p>
|
||||
<pre>
|
||||
<h2><A name="pvoid">Using <code>shared_ptr<void></code> to hold an arbitrary
|
||||
object</A></h2>
|
||||
<p>[...]</p>
|
||||
<pre>
|
||||
shared_ptr<void> pv(new X);
|
||||
</pre>
|
||||
<p>[Will correctly call <code>~X</code>.]</p>
|
||||
<p>[Can be used to strip type information: <code>shared_ptr<X></code> -> <code>(shared_ptr<void>, typeid(X))</code>]</p>
|
||||
<h2><A name="extra_data">Associating arbitrary data with heterogeneous <code>shared_ptr</code>
|
||||
<p>[Will correctly call <code>~X</code>.]</p>
|
||||
<p>[Can be used to strip type information: <code>shared_ptr<X></code> -> <code>
|
||||
(shared_ptr<void>, typeid(X))</code>]</p>
|
||||
<h2><A name="extra_data">Associating arbitrary data with heterogeneous <code>shared_ptr</code>
|
||||
instances</A></h2>
|
||||
<p>[...]</p>
|
||||
<pre>
|
||||
<p>[...]</p>
|
||||
<pre>
|
||||
typedef int Data;
|
||||
|
||||
std::map< shared_ptr<void>, Data > userData;
|
||||
@ -482,8 +576,8 @@ userData[px] = 42;
|
||||
userData[pi] = 91;
|
||||
</pre>
|
||||
<h2><A name="pre_destructor">Post-constructors and pre-destructors</A></h2>
|
||||
<p>[...]</p>
|
||||
<pre>
|
||||
<p>[...]</p>
|
||||
<pre>
|
||||
class X
|
||||
{
|
||||
public:
|
||||
@ -511,8 +605,9 @@ public:
|
||||
};
|
||||
</pre>
|
||||
<h2><A name="as_lock">Using <code>shared_ptr</code> as a CopyConstructible mutex lock</A></h2>
|
||||
<p>[Sometimes it's necessary to return a mutex lock from a function. A noncopyable lock cannot be used.]</p>
|
||||
<pre>
|
||||
<p>[Sometimes it's necessary to return a mutex lock from a function. A noncopyable
|
||||
lock cannot be used.]</p>
|
||||
<pre>
|
||||
class mutex
|
||||
{
|
||||
public:
|
||||
@ -527,8 +622,8 @@ shared_ptr<mutex> lock(mutex & m)
|
||||
return shared_ptr<mutex>(&m, mem_fn(&mutex::unlock));
|
||||
}
|
||||
</pre>
|
||||
<p>[Or to encapsulate it in a dedicated class:]</p>
|
||||
<pre>
|
||||
<p>[Or to encapsulate it in a dedicated class:]</p>
|
||||
<pre>
|
||||
class shared_lock
|
||||
{
|
||||
private:
|
||||
@ -540,14 +635,15 @@ public:
|
||||
template<class Mutex> explicit shared_lock(Mutex & m): pv((m.lock(), &m), mem_fn(&Mutex::unlock)) {}
|
||||
};
|
||||
</pre>
|
||||
<p>[Usage:]</p>
|
||||
<pre>
|
||||
<p>[Usage:]</p>
|
||||
<pre>
|
||||
shared_lock lock(m);
|
||||
</pre>
|
||||
<p>[Note that <code>shared_lock</code> is not templated on the mutex type, thanks to <code>shared_ptr<void></code>'s ability to hide type information.]</p>
|
||||
<p>[Note that <code>shared_lock</code> is not templated on the mutex type, thanks
|
||||
to <code>shared_ptr<void></code>'s ability to hide type information.]</p>
|
||||
<h2><A name="wrapper">Using <code>shared_ptr</code> to wrap member function calls</A></h2>
|
||||
<p>[http://www.research.att.com/~bs/wrapper.pdf]</p>
|
||||
<pre>
|
||||
<p>[http://www.research.att.com/~bs/wrapper.pdf]</p>
|
||||
<pre>
|
||||
template<class T> class pointer
|
||||
{
|
||||
private:
|
||||
@ -592,8 +688,9 @@ int main()
|
||||
}
|
||||
</pre>
|
||||
<h2><A name="delayed">Delayed deallocation</A></h2>
|
||||
<p>[In some situations, a single <code>px.reset()</code> can trigger an expensive deallocation in a performance-critical region.]</p>
|
||||
<pre>
|
||||
<p>[In some situations, a single <code>px.reset()</code> can trigger an expensive
|
||||
deallocation in a performance-critical region.]</p>
|
||||
<pre>
|
||||
class X; // ~X is expensive
|
||||
|
||||
class Y
|
||||
@ -608,8 +705,8 @@ public:
|
||||
}
|
||||
};
|
||||
</pre>
|
||||
<p>[Solution 1]</p>
|
||||
<pre>
|
||||
<p>[Solution 1]</p>
|
||||
<pre>
|
||||
vector< shared_ptr<void> > free_list;
|
||||
|
||||
class Y
|
||||
@ -627,8 +724,8 @@ public:
|
||||
|
||||
// periodically invoke free_list.clear() when convenient
|
||||
</pre>
|
||||
<p>[Solution 2, as above, but use a delayed deleter]</p>
|
||||
<pre>
|
||||
<p>[Solution 2, as above, but use a delayed deleter]</p>
|
||||
<pre>
|
||||
struct delayed_deleter
|
||||
{
|
||||
template<class T> void operator()(T * p)
|
||||
@ -645,8 +742,8 @@ struct delayed_deleter
|
||||
};
|
||||
</pre>
|
||||
<h2><A name="weak_without_shared">Weak pointers to objects not managed by a <code>shared_ptr</code></A></h2>
|
||||
<p>Make the object hold a <code>shared_ptr</code> to itself, using a <code>null_deleter</code>:</p>
|
||||
<pre>
|
||||
<p>Make the object hold a <code>shared_ptr</code> to itself, using a <code>null_deleter</code>:</p>
|
||||
<pre>
|
||||
class X
|
||||
{
|
||||
private:
|
||||
@ -676,12 +773,13 @@ public:
|
||||
weak_ptr<X> get_weak_ptr() const { return this_; }
|
||||
};
|
||||
</pre>
|
||||
<p>When the object's lifetime ends, <code>X::this_</code> will be destroyed, and all weak pointers will automatically expire.</p>
|
||||
<p>When the object's lifetime ends, <code>X::this_</code> will be destroyed, and
|
||||
all weak pointers will automatically expire.</p>
|
||||
<hr>
|
||||
<p>
|
||||
$Date$</p>
|
||||
<p>
|
||||
Copyright © 2003 Peter Dimov. Permission to copy, use, modify, sell and
|
||||
Copyright <EFBFBD> 2003 Peter Dimov. Permission to copy, use, modify, sell and
|
||||
distribute this document is granted provided this copyright notice appears in
|
||||
all copies. This document is provided "as is" without express or implied
|
||||
warranty, and with no claim as to its suitability for any purpose.</p>
|
||||
|
Reference in New Issue
Block a user