From f4dce1cb88aba8076b37d278d1bc18c2a78b9ee5 Mon Sep 17 00:00:00 2001
From: Peter Dimov
void f(X * p) { - shared_ptr<X> px(???); + shared_ptr<X> px(???); }
Inside f
, we'd like to create a shared_ptr
to *p
.
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: };
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(); + } +} +
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(); } -};
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.
f(p)
, where p
is a pointer: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)); +
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.
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
.
shared_ptr
instances[...]