From d7c841484a924fd9327886a0c3db442cb8e34e92 Mon Sep 17 00:00:00 2001
From: Peter Dimov
Associating arbitrary data with heterogeneous shared_ptr
instances
- Post-constructors and pre-destructors
Using shared_ptr
as a CopyConstructible mutex lock
Using shared_ptr
to wrap member function calls
Delayed deallocation
@@ -360,7 +359,7 @@ shared_ptr<X> make_shared_from_another(another_ptr<X> qx)
instance. Example:
void f(X * p) { - shared_ptr<X> px(???); + shared_ptr<X> px(???); }
Inside f
, we'd like to create a shared_ptr
to *p
.
but at construction time, px
does not exist yet, and it is
impossible to create another shared_ptr
instance that shares
ownership with it.
- Depending on context, if the inner shared_ptr
this_
doesn't
+
Depending on context, if the inner shared_ptr
this_
doesn't
need to keep the object alive, use a null_deleter
as explained
here and here. If X
is
supposed to always live on the heap, and be managed by a shared_ptr
,
@@ -463,7 +461,7 @@ public:
virtual shared_ptr<X> getX()
{
- shared_ptr<X> px(???);
+ shared_ptr<X> px(???);
return px;
}
};
@@ -500,8 +498,7 @@ public:
The library now includes a helper class template enable_shared_from_this
that can be used to encapsulate the solution:
-class impl: public X, public Y, public enable_shared_from_this<impl> +class impl: public X, public Y, public enable_shared_from_this<impl> { public: @@ -536,8 +533,8 @@ handle createProcess() }Using
-shared_ptr
to execute code on block exitIt is possible to use
+shared_ptr<void>
to automatically - execute cleanup code when control leaves a scope.
shared_ptr<void>
can automatically execute cleanup code when + control leaves a scope.
f(p)
, where p
is a pointer:f(x, y)
:shared_ptr<void> guard(static_cast<void*>(0), bind(f, x, y)); +shared_ptr<void> guard(static_cast<void*>(0), bind(f, x, y));For a more thorough treatment, see the article "Simplify Your Exception-Safe Code" by Andrei Alexandrescu and Petru Marginean, available online at http://www.cuj.com/experts/1812/alexandr.htm?topic=experts.
Using
-shared_ptr<void>
to hold an arbitrary objectIt is possible to use
+shared_ptr<void>
as a generic object - pointer similar tovoid*
. When ashared_ptr<void>
- instance constructed as:
shared_ptr<void>
can act as a generic object pointer similar + tovoid*
. When ashared_ptr<void>
instance + constructed as:shared_ptr<void> pv(new X);is destroyed, it will correctly dispose of the
X
object by @@ -566,7 +563,10 @@ handle createProcess() static_pointer_cast.Associating arbitrary data with heterogeneous
-shared_ptr
instances[...]
+
shared_ptr
andweak_ptr
supportoperator<
+ comparisons required by standard associative containers such asstd::map
. + This can be used to non-intrusively associate arbitrary data with objects + managed byshared_ptr
: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; --Post-constructors and pre-destructors
-[...]
-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; - } -};Using
-shared_ptr
as a CopyConstructible mutex lock[Sometimes it's necessary to return a mutex lock from a function. A noncopyable - lock cannot be used.]
+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
shared_ptr
+ as a mutex lock:class mutex { public: @@ -623,7 +596,8 @@ shared_ptr<mutex> lock(mutex & m) return shared_ptr<mutex>(&m, mem_fn(&mutex::unlock)); }-[Or to encapsulate it in a dedicated class:]
+Better yet, the
shared_ptr
instance acting as a lock can be + encapsulated in a dedicatedshared_lock
class: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)) {} };-[Usage:]
+
shared_lock
can now be used as:shared_lock lock(m);-[Note that
+shared_lock
is not templated on the mutex type, thanks - toshared_ptr<void>
's ability to hide type information.]Note that
shared_lock
is not templated on the mutex type, thanks to+ shared_ptr<void>
's ability to hide type information.Using
shared_ptr
to wrap member function calls[http://www.research.att.com/~bs/wrapper.pdf]
template<class T> class pointer @@ -686,8 +660,8 @@ int main() }Delayed deallocation
-[In some situations, a single
+px.reset()
can trigger an expensive - deallocation in a performance-critical region.]In some situations, a single
px.reset()
can trigger an expensive + deallocation in a performance-critical region:class X; // ~X is expensive class Y @@ -702,7 +676,9 @@ public: } };-[Solution 1]
+The 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:vector< shared_ptr<void> > free_list; class Y @@ -720,7 +696,8 @@ public: // periodically invoke free_list.clear() when convenient-[Solution 2, as above, but use a delayed deleter]
+Another variation is to move the free list logic to the construction point by + using a delayed deleter:
struct delayed_deleter { template<class T> void operator()(T * p) diff --git a/test/shared_ptr_test.cpp b/test/shared_ptr_test.cpp index 447dd9c..fd18e45 100644 --- a/test/shared_ptr_test.cpp +++ b/test/shared_ptr_test.cpp @@ -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();