Further edits, predestructor technique removed.

[SVN r17374]
This commit is contained in:
Peter Dimov
2003-02-13 18:35:13 +00:00
parent f4dce1cb88
commit d7c841484a
2 changed files with 30 additions and 54 deletions

View File

@ -32,7 +32,6 @@
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>
<A href="#wrapper">Using <code>shared_ptr</code> to wrap member function calls</A><br>
<A href="#delayed">Delayed deallocation</A><br>
@ -360,7 +359,7 @@ shared_ptr&lt;X&gt; make_shared_from_another(another_ptr&lt;X&gt; qx)
instance. Example:</p>
<pre>void f(X * p)
{
shared_ptr&lt;X&gt; px(<i>???</i>);
shared_ptr&lt;X&gt; px(<i>???</I>);
}
</pre>
<p>Inside <code>f</code>, we'd like to create a <code>shared_ptr</code> to <code>*p</code>.</p>
@ -390,7 +389,7 @@ public:
X()
{
shared_ptr&lt;X&gt; this_(<i>???</i>);
shared_ptr&lt;X&gt; this_(<i>???</I>);
}
};
</pre>
@ -401,8 +400,7 @@ public:
<P>but at construction time, <code>px</code> does not exist yet, and it is
impossible to create another <code>shared_ptr</code> instance that shares
ownership with it.</P>
<P>
Depending on context, if the inner <code>shared_ptr</code> <code>this_</code> doesn't
<P>Depending on context, if the inner <code>shared_ptr</code> <code>this_</code> doesn't
need to keep the object alive, use a <code>null_deleter</code> as explained <A href="#static">
here</A> and <A href="#weak_without_shared">here</A>. If <code>X</code> is
supposed to always live on the heap, and be managed by a <code>shared_ptr</code>,
@ -463,7 +461,7 @@ public:
virtual shared_ptr&lt;X&gt; getX()
{
shared_ptr&lt;X&gt; px(<i>???</i>);
shared_ptr&lt;X&gt; px(<i>???</I>);
return px;
}
};
@ -500,8 +498,7 @@ public:
</pre>
<p>The library now includes a helper class template <code>enable_shared_from_this</code>
that can be used to encapsulate the solution:</p>
<pre>
class impl: public X, public Y, public enable_shared_from_this&lt;impl&gt;
<pre>class impl: public X, public Y, public enable_shared_from_this&lt;impl&gt;
{
public:
@ -536,8 +533,8 @@ handle createProcess()
}
</pre>
<h2><A name="on_block_exit">Using <code>shared_ptr</code> to execute code on block exit</A></h2>
<p>It is possible to use <code>shared_ptr&lt;void&gt;</code> to automatically
execute cleanup code when control leaves a scope.</p>
<p><code>shared_ptr&lt;void&gt;</code> can automatically execute cleanup code when
control leaves a scope.</p>
<UL>
<LI>
Executing <code>f(p)</code>, where <code>p</code> is a pointer:</LI></UL>
@ -553,9 +550,9 @@ handle createProcess()
http://www.cuj.com/experts/1812/alexandr.htm?topic=experts</A>.</P>
<h2><A name="pvoid">Using <code>shared_ptr&lt;void&gt;</code> to hold an arbitrary
object</A></h2>
<p>It is possible to use <code>shared_ptr&lt;void&gt;</code> as a generic object
pointer similar to <code>void*</code>. When a <code>shared_ptr&lt;void&gt;</code>
instance constructed as:</p>
<p><code>shared_ptr&lt;void&gt;</code> can act as a generic object pointer similar
to <code>void*</code>. When a <code>shared_ptr&lt;void&gt;</code> instance
constructed as:</p>
<pre> shared_ptr&lt;void&gt; pv(new X);
</pre>
<p>is destroyed, it will correctly dispose of the <code>X</code> object by
@ -566,7 +563,10 @@ handle createProcess()
static_pointer_cast</A></code>.</p>
<h2><A name="extra_data">Associating arbitrary data with heterogeneous <code>shared_ptr</code>
instances</A></h2>
<p>[...]</p>
<p><code>shared_ptr</code> and <code>weak_ptr</code> support <code>operator&lt;</code>
comparisons required by standard associative containers such as <code>std::map</code>.
This can be used to non-intrusively associate arbitrary data with objects
managed by <code>shared_ptr</code>:</p>
<pre>typedef int Data;
std::map&lt; shared_ptr&lt;void&gt;, Data &gt; userData;
@ -577,38 +577,11 @@ shared_ptr&lt;int&gt; pi(new int(3));
userData[px] = 42;
userData[pi] = 91;
</pre>
<h2><A name="pre_destructor">Post-constructors and pre-destructors</A></h2>
<p>[...]</p>
<pre>class X
{
public:
X();
virtual void postconstructor();
virtual void predestructor() throw();
~X() throw();
struct deleter
{
void operator()(X * p)
{
p-&gt;predestructor();
delete p;
}
}
static shared_ptr&lt;X&gt; create()
{
shared_ptr&lt;X&gt; px(new X, X::deleter());
px-&gt;postconstructor(); // can throw
return px;
}
};
</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>
<p>Sometimes 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 <code>shared_ptr</code>
as a mutex lock:</p>
<pre>class mutex
{
public:
@ -623,7 +596,8 @@ shared_ptr&lt;mutex&gt; lock(mutex &amp; m)
return shared_ptr&lt;mutex&gt;(&amp;m, mem_fn(&amp;mutex::unlock));
}
</pre>
<p>[Or to encapsulate it in a dedicated class:]</p>
<p>Better yet, the <code>shared_ptr</code> instance acting as a lock can be
encapsulated in a dedicated <code>shared_lock</code> class:</p>
<pre>class shared_lock
{
private:
@ -635,11 +609,11 @@ public:
template&lt;class Mutex&gt; explicit shared_lock(Mutex &amp; m): pv((m.lock(), &amp;m), mem_fn(&amp;Mutex::unlock)) {}
};
</pre>
<p>[Usage:]</p>
<p><code>shared_lock</code> can now be used as:</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&lt;void&gt;</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&lt;void&gt;</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>template&lt;class T&gt; class pointer
@ -686,8 +660,8 @@ 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>
<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
@ -702,7 +676,9 @@ public:
}
};
</pre>
<p>[Solution 1]</p>
<p>The solution is to postpone the potential deallocation by moving <code>px</code>
to a dedicated free list that can be periodically emptied when performance and
response times are not an issue:</p>
<pre>vector&lt; shared_ptr&lt;void&gt; &gt; free_list;
class Y
@ -720,7 +696,8 @@ public:
// periodically invoke free_list.clear() when convenient
</pre>
<p>[Solution 2, as above, but use a delayed deleter]</p>
<p>Another variation is to move the free list logic to the construction point by
using a delayed deleter:</p>
<pre>struct delayed_deleter
{
template&lt;class T&gt; void operator()(T * p)

View File

@ -3154,7 +3154,6 @@ int main()
n_spt_intrusive::test();
n_spt_another_sp::test();
n_spt_shared_from_this::test();
// n_spt_post_constructors::test();
n_spt_wrap::test();
return boost::report_errors();