Directory
Implementation details
Source download
Contact information
Author's home page
|
In C++, a plain pointer can be in one of three fundamentally
different states: pointing to allocated memory, null, or
indeterminate1. For example, a plain pointer
has an indeterminate value if it was never initialized, or if
its target object has been deleted. Generally, a weak
pointer class reduces this model to just two states: a
pointer to a constructed object, or null, reporting null if the
target object has been deleted.
The weak pointers here use a slightly different approach, which
models the three plain pointer states more closely. The major
change is that the "indeterminate" state of a plain pointer is
replaced by an "invalid" state with well-defined semantics. An
attempt to access an uninitialized or invalidated weak pointer
is considered an error and raises an exception.
Using this approach, it becomes possible to compile the weak
pointers in two different modes, one of which maintains and
checks validity information and another which simply wraps a
plain pointer. Any code that functions correctly (i.e. doesn't
throw) with checking enabled, also operates correctly with the
checking disabled. This mirrors an assert macro which can be
compiled out in non-debug builds.
1Actually, there is another
possibility for a plain pointer: one-past-the-end of
array. However, it's probably never useful to have a smart
pointer to such an address, since (by definition) no object
exists there.
Implementation
This form of weak pointer is simple to implement using an
intrusive model, in which objects that can be pointed to by a
weak pointer provide a separate "validity" flag. The target
object's constructor allocates the flag and initializes it to
true (i.e. "valid") and the destructor resets the flag to
false. This means that the flag remains true throughout the
lifetime of the target object, and false thereafter. In order to
ensure that the validity flag itself doesn't disappear, any weak
pointers that require the flag maintain a counted reference to
it.
The diagram below shows what this looks like for two weak
pointers referencing a single target object. On the left, the
target object and each of the weak pointer objects have a
counted reference (shown as dark arrows) to the validity
flag. The lighter arrows represent plain pointers, which are not
involved in the management of the target object's lifetime.
|
|
|
|
Pointers to a valid object
|
|
After target destruction
|
Destruction of the target object results in the situation shown
on the right of the above diagram. The target object's
destructor has cleared the validity flag, but the two remaining
references prevent the flag from disappearing. The plain
pointers now have indeterminate values2 (indicated by the question
marks) and the weak pointers prevent any access to them.
Note that the weak pointers make no assumptions about how the
target object was allocated, so it is even possible to use them
for objects with automatic or static storage duration. This can
be useful if you are retro-fitting the pointers to existing
code, or for cases where you want to detect errors but allow
various object management methods.
2Actually, if the destructor
was invoked without deallocating the memory, the plain pointer
values would still be usable for some operations. However, the
weak pointers enter the "invalid" state as soon as the target
object is destroyed.
Source download
weak_ptr.tar.gz (4kB). A sample
implementation, including the weak pointer template, reference
counted validity flag class and a base class to provide the
intrusive support in client classes.
Usage details
[unfinished section]. Here is some slightly out of date
information from an article I was working on:
Original article (text only)
Original article with diagrams and listings
(16K zip file)
Original code (16K zip file) the original
implementation using boost::shared_ptr instead of a purpose-made
weak_ptr_flag class (slower).
Contact information
This page and the related sources are Copyright (c) 2002 by
Raoul Gough and may be used and distributed free of charge. The
author can usually be contacted via email to RaoulGough@yahoo.co.uk.
|