Boost logo

Boost :

From: Michael Anderson (michael.anderson_at_[hidden])
Date: 2007-02-28 00:22:03


Howdy everyone.
I have some code that uses pointers to member variables that I want to
switch to using boost::shared_ptrs, some of the code looks like this.

class Bar {};
class Foo
{
 public:
    Bar bar;
};

...
Foo * fooptr = new Foo;
Bar * barptr = &Foo.bar;
...

So to make this work with shared_ptrs I can do this:

class Bar {}
class Foo
{
  public:
   Foo() : bar(new Bar) {}
   shared_ptr<Bar> bar;
};

...
shared_ptr<Foo> fooptr(new Foo);
shared_ptr<Bar> barptr = fooptr->bar;
...

But this means I have to change each of the classes... which is a bit ugly.
Also it has unlinked the lifetime of the Bar and Foo objects.

So the solution I've come up with means that the Foo object only gets
destroyed when both the barptr and the fooptr are destroyed.
Unfortunately this requires additions to the shared_ptr class (the patch
is below). The changes are _very_ similar to what is used for
handling the pointer conversions and casts.

Anyway I was wondering whether this is useful to anyone else, and
whether there was any pitfalls I might have missed....
Thanks,
Mike Anderson

Example Usage :

#include <iostream>
#include "boost/shared_ptr.hpp"
class Foo
{
 public:
   double m;
   Foo() : m(1.0)
   {
     std::cout<<"creating Foo @ "<<this<<std::endl;
   }

   ~Foo()
   {
     std::cout<<"destroying Foo @ "<<this<<std::endl;
   }
};

int main()
{
 {
   boost::shared_ptr<Foo> fooptr( new Foo );
   {
       boost::shared_ptr<double> mptr = boost::member_pointer(fooptr,
&fooptr->m);
   }
   // Foo destroyed here...
 }

 {
   boost::shared_ptr<double> mptr;
   {
     boost::shared_ptr<Foo> fooptr( new Foo );
     mptr = boost::member_pointer(fooptr, &fooptr->m);
   }
   // Foo destroyed here... even though mptr is a pointer to double.
 }
}

class Bar {};
class Foo
{
 public:
    Bar bar;
};

shared_ptr<Foo> fooptr(new Foo);
shared_ptr<Bar> barptr = boost::member_ptr(fooptr, &fooptr->bar);

Patch : (not from the recent trunk of boost....)

--- shared_ptr.hpp
+++ shared_ptr.hpp
@@ -50,6 +50,7 @@
struct const_cast_tag {};
struct dynamic_cast_tag {};
struct polymorphic_cast_tag {};
+struct memberpointer_tag {};

template<class T> struct shared_ptr_traits
{
@@ -191,6 +192,12 @@
        }
    }

+ template<class Y, class M>
+ shared_ptr(shared_ptr<Y> const & r, M* member_ptr,
detail::memberpointer_tag) : px( member_ptr ), pn(r.pn)
+ {
+ + }
+
#ifndef BOOST_NO_AUTO_PTR

    template<class Y>
@@ -410,6 +417,11 @@
    return shared_static_cast<T>(r);
}

+template<class T, class M> shared_ptr<M> member_pointer( shared_ptr<T>
const & t, M* m)
+{
+ return shared_ptr<M>(t,m, detail::memberpointer_tag() );
+} +
// get_pointer() enables boost::mem_fn to recognize shared_ptr

template<class T> inline T * get_pointer(shared_ptr<T> const & p)

-- 
Michael Anderson
Chief Technology Officer
-- 
p. +61 8 8400 6496 [Adelaide, Australia]
michael.anderson_at_[hidden]
-- 
Rising Sun Research
p. +61 8 8400 6494 - f. +61 8 8400 6401
www.risingsunresearch.com 

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk