From f4dce1cb88aba8076b37d278d1bc18c2a78b9ee5 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 13 Feb 2003 16:56:07 +0000 Subject: [PATCH] More prose. [SVN r17369] --- sp_techniques.html | 107 ++++++++++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 36 deletions(-) diff --git a/sp_techniques.html b/sp_techniques.html index eb6dcfd..7b24efe 100644 --- a/sp_techniques.html +++ b/sp_techniques.html @@ -360,7 +360,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.

@@ -381,21 +381,32 @@ shared_ptr<X> make_shared_from_another(another_ptr<X> qx) will never outlive the object, use a null deleter.

Obtaining a shared_ptr (weak_ptr) to this in a constructor

-

[...]

+

Some designs require objects to register themselves on construction with a + central authority. When the registration routines take a shared_ptr, this leads + to the question how could a constructor obtain a shared_ptr to this:

class X
 {
 public:
 
     X()
     {
-        shared_ptr<X> this_(???);
+        shared_ptr<X> this_(???);
     }
 };
 
-

[Not possible in general. If X can have automatic or static - storage, and this_ doesn't need to keep the object alive, use a null_deleter. - If X is supposed to always live on the heap, and be managed by a - shared_ptr, use:]

+

In the general case, the problem cannot be solved. The X instance + being constructed can be an automatic variable or a static variable; it can be + created on the heap:

+
shared_ptr<X> px(new X);
+

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 + 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, + use a static factory function:

class X
 {
 private:
@@ -413,9 +424,11 @@ public:
 };
 

Obtaining a shared_ptr to this

-

[Sometimes it is needed to obtain a shared_ptr from this in a virtual member - function.]

-

[The transformations from above cannot be applied.]

+

Sometimes it is needed to obtain a shared_ptr from this + in a virtual member function under the assumption that this is + already managed by a shared_ptr. The transformations + described in the previous technique cannot be applied.

+

A typical example:

class X
 {
 public:
@@ -450,12 +463,12 @@ public:
 
     virtual shared_ptr<X> getX()
     {
-        shared_ptr<X> px(???);
+        shared_ptr<X> px(???);
         return px;
     }
 };
 
-

[Solution:]

+

The solution is to keep a weak pointer to this as a member in impl:

class impl: public X, public Y
 {
 private:
@@ -480,19 +493,40 @@ public:
 
     virtual shared_ptr<X> getX()
     {
-        shared_ptr<X> px = weak_this.lock();
+        shared_ptr<X> px(weak_this);
         return px;
     }
 };
 
-

[Future support planned, impl: public enable_shared_from_this<impl>.]

+

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>
+{
+public:
+
+    impl(impl const &);
+    impl & operator=(impl const &);
+
+public:
+
+    virtual void f() { ... }
+
+    virtual shared_ptr<X> getX()
+    {
+        return shared_from_this();
+    }
+}
+

Using shared_ptr as a smart counted handle

-

[Win32 API allusion]

+

Some library interfaces use opaque handles, a variation of the + incomplete class technique described above. An example:

typedef void * HANDLE;
 HANDLE CreateProcess();
 void CloseHandle(HANDLE);
 
-

[Quick wrapper]

+

Instead of a raw pointer, it is possible to use shared_ptr as the + handle and get reference counting and automatic resource management for free:

typedef shared_ptr<void> handle;
 
 handle createProcess()
@@ -500,35 +534,36 @@ handle createProcess()
     shared_ptr<void> pv(CreateProcess(), CloseHandle);
     return pv;
 }
-
-

[Better, typesafe:]

-
class handle
-{
-private:
-
-    shared_ptr<void> pv_;
-
-public:
-
-    explicit handle(HANDLE h): pv_(h, CloseHandle) {}
-    HANDLE get() { return pv_.get(); }
-};
 

Using shared_ptr to execute code on block exit

-

[1. Executing f(p), where p is a pointer:]

+

It is possible to use shared_ptr<void> to automatically + execute cleanup code when control leaves a scope.

+
    shared_ptr<void> guard(p, f);
 
-

[2. Executing arbitrary code: 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 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> pv(new X);
 
-

[Will correctly call ~X.]

-

[Can be used to strip type information: shared_ptr<X> -> - (shared_ptr<void>, typeid(X))]

+

is destroyed, it will correctly dispose of the X object by + executing ~X.

+

This propery can be used in much the same manner as a raw void* is + used to temporarily strip type information from an object pointer. A shared_ptr<void> + can later be cast back to the correct type by using + static_pointer_cast.

Associating arbitrary data with heterogeneous shared_ptr instances

[...]