From d7c841484a924fd9327886a0c3db442cb8e34e92 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 13 Feb 2003 18:35:13 +0000 Subject: [PATCH] Further edits, predestructor technique removed. [SVN r17374] --- sp_techniques.html | 83 +++++++++++++++------------------------- test/shared_ptr_test.cpp | 1 - 2 files changed, 30 insertions(+), 54 deletions(-) diff --git a/sp_techniques.html b/sp_techniques.html index 7b24efe..e523a52 100644 --- a/sp_techniques.html +++ b/sp_techniques.html @@ -32,7 +32,6 @@ object
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.

@@ -390,7 +389,7 @@ public: X() { - shared_ptr<X> this_(???); + shared_ptr<X> this_(???); } }; @@ -401,8 +400,7 @@ public:

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 exit

-

It 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.

@@ -546,16 +543,16 @@ handle createProcess() -
    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 object

-

It is possible to use shared_ptr<void> as a generic object - pointer similar to void*. When a shared_ptr<void> - instance constructed as:

+

shared_ptr<void> can act as a generic object pointer similar + to void*. When a shared_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 and weak_ptr support operator< + comparisons required by standard associative containers such as std::map. + This can be used to non-intrusively associate arbitrary data with objects + managed by shared_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 dedicated shared_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 - to shared_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();