views:

987

answers:

2

Hello, I have simple base and derived class that I want both have shared_from_this().

This simple solution:

class foo : public enable_shared_from_this<foo> {
 void foo_do_it()
 {
  cout<<"foo::do_it\n";
 }
public:
 virtual function<void()> get_callback()
 {
  return boost::bind(&foo::foo_do_it,shared_from_this());
 }
 virtual ~foo() {};
};

class bar1 : public foo , public enable_shared_from_this<bar1> {
 using enable_shared_from_this<bar1>::shared_from_this;
 void bar1_do_it()
 {
  cout<<"foo::do_it\n";
 }
public:
 virtual function<void()> get_callback()
 {
  return boost::bind(&bar1::bar1_do_it,shared_from_this());
 }
};

Causes exception tr1::bad_weak_ptr in following code:

shared_ptr<foo> ptr(shared_ptr<foo>(new bar1));
function<void()> f=ptr->get_callback();
f();

So after "googling" I have found following solution:

class bar2 : public foo {
 void bar2_do_it()
 {
  cout<<"foo::do_it\n";
 }
 shared_ptr<bar2> shared_from_this()
 {
  return boost::static_pointer_cast<bar2>(foo::shared_from_this());
 }
public:
 virtual function<void()> get_callback()
 {
  return boost::bind(&bar2::bar2_do_it,shared_from_this());
 }
};

And now it works.

Is there any better and more convinient and correct way to enable_shared_from_this for both parent and child?

Thanks

A: 

I do not think the working solution is inconvenient by the standards of C++.

Amit Kumar
+1  A: 

Sorry, but there isn't.

The problem is that shared_ptr<foo> and shared_ptr<bar1> are different types. I don't understand everything that's going on under the hood, but I think that when the constructor returns and is assigned to a shared_ptr<foo>, the internal weak_ptr<bar1> sees that nothing is pointing to it (because only a shared_ptr<bar1> would increment the counter) and resets itself. When you call bar1::shared_from_this in get_callback, you get the exception because the internal weak_ptr isn't pointing to anything.

Essentially, enable_shared_from_this only seems to work transparently from a single class in a hierarchy. If you try implementing it manually, the problem should become obvious.

Head Geek
I tried implementing it manually, and it's actually not that hard. In `My::SmartPointer<T>`, check if T is derived from `My::enableSmartFromThis`. If so, don't allocate a reference counter on the heap, but use the members of `My::enableSmartFromThis`. Now `My::GetSmartFromThis(this)` becomes trivial, it can convert `this` to a `My::enableSmartFromThis*` and find the existing reference count. You can even check if you're trying to convert from Base to Derived when only Derived derives from `My::enableSmartFromThis`.
MSalters