Boost logo

Boost Users :

Subject: [Boost-users] [Boost.Smart_ptr] global_reset (revamp) for shared_ptr
From: Robbie Morrison (robbie_at_[hidden])
Date: 2009-08-18 13:51:44


Hello Boost-Users

CAVEAT

The attached code "works" but has a major design flaw
regarding pointer conversion safety -- one which can
currently either be accepted (at your risk) or
rectified by limiting usage to one-hop inheritance.

In particular, statement [3] (see below) is processed
without complaint in unsafe mode -- when it should
ideally provoke a compile-time error.

Indeed, providing a general type-safe solution is not
without challenge (read: my knowledge of C++ has been
exhausted). If interested, member function
'Common::reVamp' would be a good place to start.

PROBLEM

I recently needed a 'shared_ptr' that could be globally
reset -- that is, any one of the owners of the
controlled resource could unilaterally replace that
resource for the benefit (perhaps) of everyone else.

This has been named "global_reset" in previous postings
-- but I have adopted the shorter word "revamp".

Moreover, it would be useful if this newly conceived
"assign_ptr" could mimic the behavior of 'shared_ptr',
whilst simultaneously providing the additional
functionality. In particular, implicit upcasting
should be maintained.

This lead me to quickly reject options like:

    shared_ptr<scoped_ptr<Resource> > ptrPtrResource;

And instead try to implement something like:

    assign_ptr<T> py(new Y());

My environment is single-threaded and issues like CPU
cycles and memory consumption are not significant. Of
more importance to me was coding at a high level -- in
part, because I imagined that any conforming solution
could subsequently be refactored to improve on
performance and safety.

SOLUTION STRATEGY

The proposed solution has parallels with the Observer
pattern and relies on 'shared_ptr' to do most of the
work. Notwithstanding the code is now considerably
more involved than I had originally envisaged.

The biggest challenge was getting a multi-step
inheritance chain to play ball with the semantics and
syntax. Consider, if you would:

    class A; // base class
    class B : public A;
    class C : public B; // and perhaps more

    assign_ptr<B> b(new C()); // C resource held by B pointer [1]
    assign_ptr<A> a = b; // resource now also held by A pointer
    a.revamp(new C()); // not so simple to implement [2]

The statement marked [2] looks reasonable. But it
offers my observer class a challenge -- namely the need
to have available the type information present during
statement [1] when re-assigning the replacement
resource to 'b' during the 'revamp' call. In addition,
the following statement should fail in some way --
ideally at compile-time:

    a.revamp(new A()); // okay for 'a', nonsensical for 'b' [3]

The following member functions are offered, noting that
the first two are already part of 'shared_ptr:'

    a.use_count() // number of owners in the pool
    a.unique() // true if use_count() == 1

    a.revamp_count() // number of revamps
    a.original() // true if revamp_count() == 0

    a.external_count() // number of owners outside the pool
    a.exclusive() // true if external_count() == 0

PRIOR DISCUSSIONS

The problem itself is noted in the Boost documentation:

    Boost Libraries
      + Smart Pointers
        + shared_ptr class template
          + Smart Pointer Programming Techniques
            + Obtaining a shared_ptr from a raw pointer

One significant thread on this topic can be found at:

  subject = shared_ptr and global reset
  date = Feb-2009
  http://thread.gmane.org/gmane.comp.lib.boost.user/45032/focus=45034

CODE

A single *.cc file is attached. This code was
developed using:

    boost : 1.39.0 (built from source)
    compiler : GCC g++ 4.1.2 (2006)
    kernel : Ubuntu 6.10 Linux 2.6.17-12-generic
    hardware : 1.4GHz Intel Celeron M / 512MiB RAM

DESIGN SUMMARY

This section gives a brief outline of the design
thinking I used. Note too that the code is also
extensively documented.

The point-of-entry is class template 'assign_ptr'.
This holds its own controlled resource pointer, just
like 'shared_ptr', but in this case, as a 'shared_ptr'.
It also holds a 'shared_ptr' to a class 'Common' object
(aka "Subject" under the Observer pattern). Class
'Common' manages a list of its 'Client's (aka
"Observers") and, in doing so, defines the pool. The
derived class template 'ClientImp' duly retains the
type of its associated 'assign_ptr'.

The various 'assign_ptr' member functions pass requests
to the 'Common' object, which responds accordingly.
Most of these member functions were declared above.
Class 'Common', in turn, contains the management
functions 'attach' and 'detach' and the interventionist
function 'reVamp'.

The remainder of the 'assign_ptr' implementation is
aimed at providing a similar interface to 'shared_ptr'.

Finally, everything is placed in namespace 'xeona'.

LITERATURE

Alexandrescu (2001, ch7, pp157-195) devotes a chapter
to smart pointers and the underlying design trade-offs
-- however "revamping" is not considered:

  Alexandrescu, Andrei. 2001. Modern C++ design :
    generic programming and design patterns applied.
    Addison-Wesley, Boston, USA. ISBN 0-201-70431-5.

The notion of "revamping" is never far away in Meyers
(1996 item29 pp183-213) reference counting example, but
neither is it directly mentioned.

  Meyers, Scott. 1996. More effective C++ : 35 new
    ways to improve your programs and design.
    Addison-Wesley, Boston, USA. ISBN 0-201-63371-X.

Some ideas regarding the use of Boost.Any came from the
following book (which I found both instructional and
nicely written):

  Karlsson, Bjoern. 2006. Beyond the C++ Standard
    Library : an introduction to Boost.
    Addison-Wesley, Upper Saddle River, New Jersey,
    USA. ISBN 0-321-13354-4.

The following web article offered some insights on
solutions:

  Becker, Thomas. 2007. On the tension between
    object-oriented and generic programming in C++ :
    and what type erasure can do about it. C++ Source.
    [http://www.artima.com/cppsource/type_erasure1.html]

Finally, Dattatri (2002 pp487-496) provides an
implementation of counted pointers and discusses the
design issues in some depth.

  Dattatri, Kayshav. 2002. C++ : effective-object
    oriented software construction : concepts,
    principles, industrial strategies and practices --
    Second edition. Prentice Hall PTR, Upper Saddle
    River, New Jersey, USA. ISBN 0-13-086769-1.

ABOUT THE AUTHOR

I am a PhD student writing a policy-oriented energy
system simulation at the Institute for Energy
Engineering (IET), Technical University of Berlin
(TU-Berlin), Germany. I have never coded
professionally, but consider myself reasonably
competent in terms of scientific programming.

---
I am happy to take comments, suggestions, and patches
and will post an update in due course.
Please note that I will be checking my email only
infrequently over the next four weeks or so.
best wishes to all
Robbie Morrison
---
PhD student -- policy-oriented energy system simulation
Technical University of Berlin (TU-Berlin), Germany
University email (redirected) : morrison_at_[hidden]
Webmail (preferred)           : robbie_at_[hidden]
[from IMAP client]



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net