forked from boostorg/smart_ptr
Minor edits.
[SVN r17335]
This commit is contained in:
@ -7,8 +7,7 @@
|
|||||||
<body text="#000000" bgColor="#ffffff">
|
<body text="#000000" bgColor="#ffffff">
|
||||||
<h1><IMG height="86" alt="c++boost.gif (8819 bytes)" src="../../c++boost.gif" width="277" align="middle">Smart
|
<h1><IMG height="86" alt="c++boost.gif (8819 bytes)" src="../../c++boost.gif" width="277" align="middle">Smart
|
||||||
pointer programming techniques</h1>
|
pointer programming techniques</h1>
|
||||||
<p>
|
<p><A href="#incomplete">Using incomplete classes for implementation hiding</A><br>
|
||||||
<A href="#incomplete">Using incomplete classes for implementation hiding</A><br>
|
|
||||||
<A href="#pimpl">The "Pimpl" idiom</A><br>
|
<A href="#pimpl">The "Pimpl" idiom</A><br>
|
||||||
<A href="#abstract">Using abstract classes for implementation hiding</A><br>
|
<A href="#abstract">Using abstract classes for implementation hiding</A><br>
|
||||||
<A href="#preventing_delete">Preventing <code>delete px.get()</code></A><br>
|
<A href="#preventing_delete">Preventing <code>delete px.get()</code></A><br>
|
||||||
@ -42,8 +41,7 @@
|
|||||||
<h2><A name="incomplete">Using incomplete classes for implementation hiding</A></h2>
|
<h2><A name="incomplete">Using incomplete classes for implementation hiding</A></h2>
|
||||||
<p>A proven technique (that works in C, too) for separating interface from
|
<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>
|
implementation is to use a pointer to an incomplete class as an opaque handle:</p>
|
||||||
<pre>
|
<pre>class FILE;
|
||||||
class FILE;
|
|
||||||
|
|
||||||
FILE * fopen(char const * name, char const * mode);
|
FILE * fopen(char const * name, char const * mode);
|
||||||
void fread(FILE * f, void * data, size_t size);
|
void fread(FILE * f, void * data, size_t size);
|
||||||
@ -51,8 +49,7 @@ void fclose(FILE * f);
|
|||||||
</pre>
|
</pre>
|
||||||
<p>It is possible to express the above interface using <code>shared_ptr</code>,
|
<p>It is possible to express the above interface using <code>shared_ptr</code>,
|
||||||
eliminating the need to manually call <code>fclose</code>:</p>
|
eliminating the need to manually call <code>fclose</code>:</p>
|
||||||
<pre>
|
<pre>class FILE;
|
||||||
class FILE;
|
|
||||||
|
|
||||||
shared_ptr<FILE> fopen(char const * name, char const * mode);
|
shared_ptr<FILE> fopen(char const * name, char const * mode);
|
||||||
void fread(shared_ptr<FILE> f, void * data, size_t size);
|
void fread(shared_ptr<FILE> f, void * data, size_t size);
|
||||||
@ -65,8 +62,7 @@ void fread(shared_ptr<FILE> f, void * data, size_t size);
|
|||||||
<p>A C++ specific variation of the incomplete class pattern is the "Pimpl" idiom.
|
<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
|
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>
|
forwarding facade. <code>shared_ptr</code> can be used to implement a "Pimpl":</p>
|
||||||
<pre>
|
<pre>// file.hpp:
|
||||||
// file.hpp:
|
|
||||||
|
|
||||||
class file
|
class file
|
||||||
{
|
{
|
||||||
@ -84,8 +80,7 @@ public:
|
|||||||
void read(void * data, size_t size);
|
void read(void * data, size_t size);
|
||||||
};
|
};
|
||||||
</pre>
|
</pre>
|
||||||
<pre>
|
<pre>// file.cpp:
|
||||||
// file.cpp:
|
|
||||||
|
|
||||||
#include "file.hpp"
|
#include "file.hpp"
|
||||||
|
|
||||||
@ -124,8 +119,7 @@ void file::read(void * data, size_t size)
|
|||||||
sometimes called "interfaces" and the pattern is known as "interface-based
|
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
|
programming". Again, <code>shared_ptr</code> can be used as the return type of
|
||||||
the factory functions:</p>
|
the factory functions:</p>
|
||||||
<pre>
|
<pre>// X.hpp:
|
||||||
// X.hpp:
|
|
||||||
|
|
||||||
class X
|
class X
|
||||||
{
|
{
|
||||||
@ -141,8 +135,7 @@ protected:
|
|||||||
|
|
||||||
shared_ptr<X> createX();
|
shared_ptr<X> createX();
|
||||||
</pre>
|
</pre>
|
||||||
<pre>
|
<pre>-- X.cpp:
|
||||||
-- X.cpp:
|
|
||||||
|
|
||||||
class X_impl: public X
|
class X_impl: public X
|
||||||
{
|
{
|
||||||
@ -181,8 +174,7 @@ shared_ptr<X> createX()
|
|||||||
being managed by <code>shared_ptr</code>. The previous technique showed one
|
being managed by <code>shared_ptr</code>. The previous technique showed one
|
||||||
possible approach, using a protected destructor. Another alternative is to use
|
possible approach, using a protected destructor. Another alternative is to use
|
||||||
a private deleter:</p>
|
a private deleter:</p>
|
||||||
<pre>
|
<pre>class X
|
||||||
class X
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -210,8 +202,7 @@ public:
|
|||||||
<h2><A name="array">Using a <code>shared_ptr</code> to hold a pointer to an array</A></h2>
|
<h2><A name="array">Using a <code>shared_ptr</code> to hold a pointer to an array</A></h2>
|
||||||
<p>A <code>shared_ptr</code> can be used to hold a pointer to an array allocated
|
<p>A <code>shared_ptr</code> can be used to hold a pointer to an array allocated
|
||||||
with <code>new[]</code>:</p>
|
with <code>new[]</code>:</p>
|
||||||
<pre>
|
<pre>shared_ptr<X> px(new X[1], <A href="../utility/checked_delete.html" >checked_array_deleter</A><X>());
|
||||||
shared_ptr<X> px(new X[1], <A href="../utility/checked_delete.html">checked_array_deleter</A><X>());
|
|
||||||
</pre>
|
</pre>
|
||||||
<p>Note, however, that <code><A href="shared_array.htm">shared_array</A></code> is
|
<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,
|
often preferable, if this is an option. It has an array-specific interface,
|
||||||
@ -224,15 +215,13 @@ shared_ptr<X> px(new X[1], <A href="../utility/checked_delete.html">checke
|
|||||||
to encapsulate allocation details. As an example, consider this interface,
|
to encapsulate allocation details. As an example, consider this interface,
|
||||||
where <code>CreateX</code> might allocate <code>X</code> from its own private
|
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>
|
heap, <code>~X</code> may be inaccessible, or <code>X</code> may be incomplete:</p>
|
||||||
<pre>
|
<pre>X * CreateX();
|
||||||
X * CreateX();
|
|
||||||
void DestroyX(X *);
|
void DestroyX(X *);
|
||||||
</pre>
|
</pre>
|
||||||
<p>The only way to reliably destroy a pointer returned by <code>CreateX</code> is
|
<p>The only way to reliably destroy a pointer returned by <code>CreateX</code> is
|
||||||
to call <code>DestroyX</code>.</p>
|
to call <code>DestroyX</code>.</p>
|
||||||
<P>Here is how a <code>shared_ptr</code>-based wrapper may look like:</P>
|
<P>Here is how a <code>shared_ptr</code>-based wrapper may look like:</P>
|
||||||
<pre>
|
<pre>shared_ptr<X> createX()
|
||||||
shared_ptr<X> createX()
|
|
||||||
{
|
{
|
||||||
shared_ptr<X> px(CreateX(), DestroyX);
|
shared_ptr<X> px(CreateX(), DestroyX);
|
||||||
return px;
|
return px;
|
||||||
@ -246,14 +235,12 @@ shared_ptr<X> createX()
|
|||||||
existing object, so that the <code>shared_ptr</code> does not attempt to
|
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
|
destroy the object when there are no more references left. As an example, the
|
||||||
factory function:</p>
|
factory function:</p>
|
||||||
<pre>
|
<pre>shared_ptr<X> createX();
|
||||||
shared_ptr<X> createX();
|
|
||||||
</pre>
|
</pre>
|
||||||
<p>in certain situations may need to return a pointer to a statically allocated <code>X</code>
|
<p>in certain situations may need to return a pointer to a statically allocated <code>X</code>
|
||||||
instance.</p>
|
instance.</p>
|
||||||
<P>The solution is to use a custom deleter that does nothing:</P>
|
<P>The solution is to use a custom deleter that does nothing:</P>
|
||||||
<pre>
|
<pre>struct null_deleter
|
||||||
struct null_deleter
|
|
||||||
{
|
{
|
||||||
void operator()(void const *) const
|
void operator()(void const *) const
|
||||||
{
|
{
|
||||||
@ -274,11 +261,10 @@ shared_ptr<X> createX()
|
|||||||
functions that manipulate it. <code>AddRef()</code> increments the count. <code>Release()</code>
|
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>
|
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>
|
<P>It is possible to hold a pointer to a COM object in a <code>shared_ptr</code>:</P>
|
||||||
<pre>
|
<pre>shared_ptr<IWhatever> make_shared_from_COM(IWhatever * p)
|
||||||
shared_ptr<IWhatever> make_shared_from_COM(IWhatever * p)
|
|
||||||
{
|
{
|
||||||
p->AddRef();
|
p->AddRef();
|
||||||
shared_ptr<IWhatever> pw(p, <A href="../bind/mem_fn.html">mem_fn</A>(&IWhatever::Release));
|
shared_ptr<IWhatever> pw(p, <A href="../bind/mem_fn.html" >mem_fn</A>(&IWhatever::Release));
|
||||||
return pw;
|
return pw;
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
@ -292,8 +278,7 @@ shared_ptr<IWhatever> make_shared_from_COM(IWhatever * p)
|
|||||||
<p>This is a generalization of the above technique. The example assumes that the
|
<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>,
|
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>
|
<code>intrusive_ptr_add_ref</code> and <code>intrusive_ptr_release</code>:</p>
|
||||||
<pre>
|
<pre>template<class T> struct intrusive_deleter
|
||||||
template<class T> struct intrusive_deleter
|
|
||||||
{
|
{
|
||||||
void operator()(T * p)
|
void operator()(T * p)
|
||||||
{
|
{
|
||||||
@ -316,8 +301,7 @@ shared_ptr<X> make_shared_from_intrusive(X * p)
|
|||||||
counted or linked smart pointer.</p>
|
counted or linked smart pointer.</p>
|
||||||
<P>It is possible to exploit <code>shared_ptr</code>'s custom deleter feature to
|
<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>
|
wrap this existing smart pointer behind a <code>shared_ptr</code> facade:</P>
|
||||||
<pre>
|
<pre>template<class P> struct smart_pointer_deleter
|
||||||
template<class P> struct smart_pointer_deleter
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -356,8 +340,7 @@ shared_ptr<X> make_shared_from_another(another_ptr<X> qx)
|
|||||||
<P>Another twist is that it is possible, given the above <code>shared_ptr</code> instance,
|
<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">
|
to recover the original smart pointer, using <code><A href="shared_ptr.htm#get_deleter">
|
||||||
get_deleter</A></code>:</P>
|
get_deleter</A></code>:</P>
|
||||||
<pre>
|
<pre>void extract_another_from_shared(shared_ptr<X> px)
|
||||||
void extract_another_from_shared(shared_ptr<X> px)
|
|
||||||
{
|
{
|
||||||
typedef smart_pointer_deleter< another_ptr<X> > deleter;
|
typedef smart_pointer_deleter< another_ptr<X> > deleter;
|
||||||
|
|
||||||
@ -375,42 +358,37 @@ void extract_another_from_shared(shared_ptr<X> px)
|
|||||||
<p>Sometimes it is necessary to obtain a <code>shared_ptr</code> given a raw
|
<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>
|
pointer to an object that is already managed by another <code>shared_ptr</code>
|
||||||
instance. Example:</p>
|
instance. Example:</p>
|
||||||
<pre>
|
<pre>void f(X * p)
|
||||||
void f(X * p)
|
|
||||||
{
|
{
|
||||||
shared_ptr<X> px(<i>???</i>);
|
shared_ptr<X> px(<i>???</I>);
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<p>Inside <code>f</code>, we'd like to create a <code>shared_ptr</code> to <code>*p</code>.</p>
|
<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>
|
<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>
|
to take a <code>shared_ptr</code>, if possible:</P>
|
||||||
<pre>
|
<pre>void f(shared_ptr<X> px);
|
||||||
void f(shared_ptr<X> px);
|
|
||||||
</pre>
|
</pre>
|
||||||
<p>The same transformation can be used for nonvirtual member functions, to convert
|
<p>The same transformation can be used for nonvirtual member functions, to convert
|
||||||
the implicit <code>this</code>:</p>
|
the implicit <code>this</code>:</p>
|
||||||
<pre>
|
<pre>void X::f(int m);
|
||||||
void X::f(int m);
|
|
||||||
</pre>
|
</pre>
|
||||||
<p>would become a free function with a <code>shared_ptr</code> first argument:</p>
|
<p>would become a free function with a <code>shared_ptr</code> first argument:</p>
|
||||||
<pre>
|
<pre>void f(shared_ptr<X> this_, int m);
|
||||||
void f(shared_ptr<X> this_, int m);
|
|
||||||
</pre>
|
</pre>
|
||||||
<p>If <code>f</code> cannot be changed, but <code>X</code> has an embedded
|
<p>If <code>f</code> cannot be changed, but <code>X</code> uses intrusive counting,
|
||||||
reference count, use <code><A href="#intrusive">make_shared_from_intrusive</A></code>
|
use <code><A href="#intrusive">make_shared_from_intrusive</A></code> described
|
||||||
described above. Or, if it's known that the <code>shared_ptr</code> created in <code>
|
above. Or, if it's known that the <code>shared_ptr</code> created in <code>f</code>
|
||||||
f</code> will never outlive the object, use <A href="#static">a null deleter</A>.</p>
|
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>)
|
<h2><A name="in_constructor">Obtaining a <code>shared_ptr</code> (<code>weak_ptr</code>)
|
||||||
to <code>this</code> in a constructor</A></h2>
|
to <code>this</code> in a constructor</A></h2>
|
||||||
<p>[...]</p>
|
<p>[...]</p>
|
||||||
<pre>
|
<pre>class X
|
||||||
class X
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
X()
|
X()
|
||||||
{
|
{
|
||||||
shared_ptr<X> this_(<i>???</i>);
|
shared_ptr<X> this_(<i>???</I>);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</pre>
|
</pre>
|
||||||
@ -418,8 +396,7 @@ public:
|
|||||||
storage, and <code>this_</code> doesn't need to keep the object alive, use a <code>null_deleter</code>.
|
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>
|
If <code>X</code> is supposed to always live on the heap, and be managed by a <code>
|
||||||
shared_ptr</code>, use:]</p>
|
shared_ptr</code>, use:]</p>
|
||||||
<pre>
|
<pre>class X
|
||||||
class X
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -439,8 +416,7 @@ public:
|
|||||||
<p>[Sometimes it is needed to obtain a shared_ptr from this in a virtual member
|
<p>[Sometimes it is needed to obtain a shared_ptr from this in a virtual member
|
||||||
function.]</p>
|
function.]</p>
|
||||||
<p>[The transformations from above cannot be applied.]</p>
|
<p>[The transformations from above cannot be applied.]</p>
|
||||||
<pre>
|
<pre>class X
|
||||||
class X
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -474,14 +450,13 @@ public:
|
|||||||
|
|
||||||
virtual shared_ptr<X> getX()
|
virtual shared_ptr<X> getX()
|
||||||
{
|
{
|
||||||
shared_ptr<X> px(<i>???</i>);
|
shared_ptr<X> px(<i>???</I>);
|
||||||
return px;
|
return px;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</pre>
|
</pre>
|
||||||
<p>[Solution:]</p>
|
<p>[Solution:]</p>
|
||||||
<pre>
|
<pre>class impl: public X, public Y
|
||||||
class impl: public X, public Y
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -513,14 +488,12 @@ public:
|
|||||||
<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>
|
<h2><A name="handle">Using <code>shared_ptr</code> as a smart counted handle</A></h2>
|
||||||
<p>[Win32 API allusion]</p>
|
<p>[Win32 API allusion]</p>
|
||||||
<pre>
|
<pre>typedef void * HANDLE;
|
||||||
typedef void * HANDLE;
|
|
||||||
HANDLE CreateProcess();
|
HANDLE CreateProcess();
|
||||||
void CloseHandle(HANDLE);
|
void CloseHandle(HANDLE);
|
||||||
</pre>
|
</pre>
|
||||||
<p>[Quick wrapper]</p>
|
<p>[Quick wrapper]</p>
|
||||||
<pre>
|
<pre>typedef shared_ptr<void> handle;
|
||||||
typedef shared_ptr<void> handle;
|
|
||||||
|
|
||||||
handle createProcess()
|
handle createProcess()
|
||||||
{
|
{
|
||||||
@ -529,8 +502,7 @@ handle createProcess()
|
|||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<p>[Better, typesafe:]</p>
|
<p>[Better, typesafe:]</p>
|
||||||
<pre>
|
<pre>class handle
|
||||||
class handle
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -544,18 +516,15 @@ public:
|
|||||||
</pre>
|
</pre>
|
||||||
<h2><A name="on_block_exit">Using <code>shared_ptr</code> to execute code on block exit</A></h2>
|
<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>
|
<p>[1. Executing <code>f(p)</code>, where <code>p</code> is a pointer:]</p>
|
||||||
<pre>
|
<pre> shared_ptr<void> guard(p, f);
|
||||||
shared_ptr<void> guard(p, f);
|
|
||||||
</pre>
|
</pre>
|
||||||
<p>[2. Executing arbitrary code: <code>f(x, y)</code>:]</p>
|
<p>[2. Executing arbitrary code: <code>f(x, y)</code>:]</p>
|
||||||
<pre>
|
<pre> shared_ptr<void> guard(static_cast<void*>(0), bind(f, x, y));
|
||||||
shared_ptr<void> guard(static_cast<void*>(0), bind(f, x, y));
|
|
||||||
</pre>
|
</pre>
|
||||||
<h2><A name="pvoid">Using <code>shared_ptr<void></code> to hold an arbitrary
|
<h2><A name="pvoid">Using <code>shared_ptr<void></code> to hold an arbitrary
|
||||||
object</A></h2>
|
object</A></h2>
|
||||||
<p>[...]</p>
|
<p>[...]</p>
|
||||||
<pre>
|
<pre> shared_ptr<void> pv(new X);
|
||||||
shared_ptr<void> pv(new X);
|
|
||||||
</pre>
|
</pre>
|
||||||
<p>[Will correctly call <code>~X</code>.]</p>
|
<p>[Will correctly call <code>~X</code>.]</p>
|
||||||
<p>[Can be used to strip type information: <code>shared_ptr<X></code> -> <code>
|
<p>[Can be used to strip type information: <code>shared_ptr<X></code> -> <code>
|
||||||
@ -563,8 +532,7 @@ public:
|
|||||||
<h2><A name="extra_data">Associating arbitrary data with heterogeneous <code>shared_ptr</code>
|
<h2><A name="extra_data">Associating arbitrary data with heterogeneous <code>shared_ptr</code>
|
||||||
instances</A></h2>
|
instances</A></h2>
|
||||||
<p>[...]</p>
|
<p>[...]</p>
|
||||||
<pre>
|
<pre>typedef int Data;
|
||||||
typedef int Data;
|
|
||||||
|
|
||||||
std::map< shared_ptr<void>, Data > userData;
|
std::map< shared_ptr<void>, Data > userData;
|
||||||
// or std::map< weak_ptr<void>, Data > userData; to not affect the lifetime
|
// or std::map< weak_ptr<void>, Data > userData; to not affect the lifetime
|
||||||
@ -577,8 +545,7 @@ userData[pi] = 91;
|
|||||||
</pre>
|
</pre>
|
||||||
<h2><A name="pre_destructor">Post-constructors and pre-destructors</A></h2>
|
<h2><A name="pre_destructor">Post-constructors and pre-destructors</A></h2>
|
||||||
<p>[...]</p>
|
<p>[...]</p>
|
||||||
<pre>
|
<pre>class X
|
||||||
class X
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -607,8 +574,7 @@ public:
|
|||||||
<h2><A name="as_lock">Using <code>shared_ptr</code> as a CopyConstructible mutex lock</A></h2>
|
<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
|
<p>[Sometimes it's necessary to return a mutex lock from a function. A noncopyable
|
||||||
lock cannot be used.]</p>
|
lock cannot be used.]</p>
|
||||||
<pre>
|
<pre>class mutex
|
||||||
class mutex
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -623,8 +589,7 @@ shared_ptr<mutex> lock(mutex & m)
|
|||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<p>[Or to encapsulate it in a dedicated class:]</p>
|
<p>[Or to encapsulate it in a dedicated class:]</p>
|
||||||
<pre>
|
<pre>class shared_lock
|
||||||
class shared_lock
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -636,15 +601,13 @@ public:
|
|||||||
};
|
};
|
||||||
</pre>
|
</pre>
|
||||||
<p>[Usage:]</p>
|
<p>[Usage:]</p>
|
||||||
<pre>
|
<pre> shared_lock lock(m);
|
||||||
shared_lock lock(m);
|
|
||||||
</pre>
|
</pre>
|
||||||
<p>[Note that <code>shared_lock</code> is not templated on the mutex type, thanks
|
<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>
|
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>
|
<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>
|
<p>[http://www.research.att.com/~bs/wrapper.pdf]</p>
|
||||||
<pre>
|
<pre>template<class T> class pointer
|
||||||
template<class T> class pointer
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -690,8 +653,7 @@ int main()
|
|||||||
<h2><A name="delayed">Delayed deallocation</A></h2>
|
<h2><A name="delayed">Delayed deallocation</A></h2>
|
||||||
<p>[In some situations, a single <code>px.reset()</code> can trigger an expensive
|
<p>[In some situations, a single <code>px.reset()</code> can trigger an expensive
|
||||||
deallocation in a performance-critical region.]</p>
|
deallocation in a performance-critical region.]</p>
|
||||||
<pre>
|
<pre>class X; // ~X is expensive
|
||||||
class X; // ~X is expensive
|
|
||||||
|
|
||||||
class Y
|
class Y
|
||||||
{
|
{
|
||||||
@ -706,8 +668,7 @@ public:
|
|||||||
};
|
};
|
||||||
</pre>
|
</pre>
|
||||||
<p>[Solution 1]</p>
|
<p>[Solution 1]</p>
|
||||||
<pre>
|
<pre>vector< shared_ptr<void> > free_list;
|
||||||
vector< shared_ptr<void> > free_list;
|
|
||||||
|
|
||||||
class Y
|
class Y
|
||||||
{
|
{
|
||||||
@ -725,8 +686,7 @@ public:
|
|||||||
// periodically invoke free_list.clear() when convenient
|
// periodically invoke free_list.clear() when convenient
|
||||||
</pre>
|
</pre>
|
||||||
<p>[Solution 2, as above, but use a delayed deleter]</p>
|
<p>[Solution 2, as above, but use a delayed deleter]</p>
|
||||||
<pre>
|
<pre>struct delayed_deleter
|
||||||
struct delayed_deleter
|
|
||||||
{
|
{
|
||||||
template<class T> void operator()(T * p)
|
template<class T> void operator()(T * p)
|
||||||
{
|
{
|
||||||
@ -743,8 +703,7 @@ struct delayed_deleter
|
|||||||
</pre>
|
</pre>
|
||||||
<h2><A name="weak_without_shared">Weak pointers to objects not managed by a <code>shared_ptr</code></A></h2>
|
<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>
|
<p>Make the object hold a <code>shared_ptr</code> to itself, using a <code>null_deleter</code>:</p>
|
||||||
<pre>
|
<pre>class X
|
||||||
class X
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -776,10 +735,8 @@ public:
|
|||||||
<p>When the object's lifetime ends, <code>X::this_</code> will be destroyed, and
|
<p>When the object's lifetime ends, <code>X::this_</code> will be destroyed, and
|
||||||
all weak pointers will automatically expire.</p>
|
all weak pointers will automatically expire.</p>
|
||||||
<hr>
|
<hr>
|
||||||
<p>
|
<p>$Date$</p>
|
||||||
$Date$</p>
|
<p>Copyright <20> 2003 Peter Dimov. Permission to copy, use, modify, sell and
|
||||||
<p>
|
|
||||||
Copyright <20> 2003 Peter Dimov. Permission to copy, use, modify, sell and
|
|
||||||
distribute this document is granted provided this copyright notice appears in
|
distribute this document is granted provided this copyright notice appears in
|
||||||
all copies. This document is provided "as is" without express or implied
|
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>
|
warranty, and with no claim as to its suitability for any purpose.</p>
|
||||||
|
Reference in New Issue
Block a user