forked from boostorg/smart_ptr
Further edits, predestructor technique removed.
[SVN r17374]
This commit is contained in:
@ -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<X> make_shared_from_another(another_ptr<X> qx)
|
||||
instance. Example:</p>
|
||||
<pre>void f(X * p)
|
||||
{
|
||||
shared_ptr<X> px(<i>???</i>);
|
||||
shared_ptr<X> 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<X> this_(<i>???</i>);
|
||||
shared_ptr<X> 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<X> getX()
|
||||
{
|
||||
shared_ptr<X> px(<i>???</i>);
|
||||
shared_ptr<X> 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<impl>
|
||||
<pre>class impl: public X, public Y, public enable_shared_from_this<impl>
|
||||
{
|
||||
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<void></code> to automatically
|
||||
execute cleanup code when control leaves a scope.</p>
|
||||
<p><code>shared_ptr<void></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<void></code> to hold an arbitrary
|
||||
object</A></h2>
|
||||
<p>It is possible to use <code>shared_ptr<void></code> as a generic object
|
||||
pointer similar to <code>void*</code>. When a <code>shared_ptr<void></code>
|
||||
instance constructed as:</p>
|
||||
<p><code>shared_ptr<void></code> can act as a generic object pointer similar
|
||||
to <code>void*</code>. When a <code>shared_ptr<void></code> instance
|
||||
constructed as:</p>
|
||||
<pre> shared_ptr<void> 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<</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< shared_ptr<void>, Data > userData;
|
||||
@ -577,38 +577,11 @@ shared_ptr<int> 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->predestructor();
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
static shared_ptr<X> create()
|
||||
{
|
||||
shared_ptr<X> px(new X, X::deleter());
|
||||
px->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<mutex> lock(mutex & m)
|
||||
return shared_ptr<mutex>(&m, mem_fn(&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<class Mutex> explicit shared_lock(Mutex & m): pv((m.lock(), &m), mem_fn(&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<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>template<class T> 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< shared_ptr<void> > 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<class T> void operator()(T * p)
|
||||
|
@ -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();
|
||||
|
Reference in New Issue
Block a user