[Boost-users] How shared_from_this() work when it inherited from more than one time

1,675 views
Skip to first unread message

R. P. Janaka

unread,
Aug 8, 2009, 5:40:19 AM8/8/09
to boost...@lists.boost.org

please can anyone explain the reason for the following behavior

#include <iostream>
#include <boost/enable_shared_from_this.hpp>

using namespace std;


class A;
typedef boost::shared_ptr<A> A_sptr_t;

class B;
typedef boost::shared_ptr<B> B_sptr_t;

class A : public boost::enable_shared_from_this<A>
{
public:
A() {}
virtual ~A() {}
};


class B : public A, public boost::enable_shared_from_this<B>
{
public:
B() {}
virtual ~B() {}

void f(void)
{
cout << "this is working " << boost::enable_shared_from_this<B>::shared_from_this() << endl;
}
};


int main()
{
B_sptr_t b(new B());
b->f();
return 0;
}




the program will be terminated with the following message

terminate called after throwing an instance of 'boost::bad_weak_ptr'
what(): boost::bad_weak_ptr
Aborted


--
Regards,
R. P. Janaka

Christian Holmquist

unread,
Aug 9, 2009, 7:03:10 PM8/9/09
to boost...@lists.boost.org
void f(void)
{
cout << "this is working " << boost::enable_shared_from_this<B>::shared_from_this() << endl;
}
};

You create an empty enable_shared_from_this<B>, then call shared_from_this() on that one which is of course empty. Intended usage is


class B : public A, public boost::enable_shared_from_this<B>
{
public:
B() {}
virtual ~B() {}

void f(void)
{
cout << "this is working " << shared_from_this() << endl;
                                          // ^^^^^^^^^^^^^^^^^^^^^^
}
};

This is not the only error though, Since you're deriving from enable_shared_from_this two times, the above will give an ambiguous call error (did you mean enable_shared_from_this<A> or enable_shared_from_this<B>).

Since you're not calling shared_from_this() in A, I suggest you remove enable_shared_from_this<A> altogether.


/ christian
 
_______________________________________________
Boost-users mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users

R. P. Janaka

unread,
Aug 10, 2009, 12:54:08 AM8/10/09
to boost...@lists.boost.org
Since you're not calling shared_from_this() in A, I suggest you remove enable_shared_from_this<A> altogether.

But in my case there is no option like this (Class A is a base library class). So I have to do this.



void f(void)
{
cout << "this is working " << boost::enable_shared_from_this<B>::shared_from_this() << endl;
}
};

You create an empty enable_shared_from_this<B>, then call shared_from_this() on that one which is of course empty.

I did the above to avoid the ambiguous call error
So how can I specify that i am calling the shared_from_this() in class B....?

Björn Karlsson

unread,
Aug 10, 2009, 3:04:45 AM8/10/09
to boost...@lists.boost.org
Hello R.P,

Inheriting from enable_shared_from_this more than once is not a good idea.

> From: boost-use...@lists.boost.org [mailto:boost-users-
> bou...@lists.boost.org] On Behalf Of R. P. Janaka
> Sent: Monday, August 10, 2009 6:54 AM
> To: boost...@lists.boost.org
> Subject: Re: [Boost-users] How shared_from_this() work when it
> inherited from more than one time
>
> But in my case there is no option like this (Class A is a base library
> class). So I have to do this.
>

Don't let B inherit from enable_shared_from_this. You've already done that in A. So your question then becomes "how do I retrieve a shared_ptr<B> from this?". Here's how:

boost::shared_dynamic_cast<B, A>(shared_from_this());

In the example you've provided, it would also be safe to use boost::shared_static_cast.
To conclude: You should only inherit from enable_shared_from_this in A, and B should only inherit from A.


> I did the above to avoid the ambiguous call error So how can I specify
> that i am calling the shared_from_this() in class B....?

You did. But the problem is that you have two weak_ptrs -- one weak_ptr<A> and one weak_ptr<B> -- and only one of them will be initialized correctly when you create the smart pointer. (If you're interested in debugging your case to really understand what happens, have a look at the function
sp_enable_shared_from_this() in shared_ptr.hpp.)

Does that help?

Cheers,
Bjorn Karlsson

Igor R

unread,
Aug 10, 2009, 4:05:46 AM8/10/09
to boost...@lists.boost.org
> Don't let B inherit from enable_shared_from_this. You've already done that in A. So your question then becomes "how do I retrieve a shared_ptr<B> from this?". Here's how:
>
>  boost::shared_dynamic_cast<B, A>(shared_from_this());

Why not:
boost::static_pointer_cast<B>(shared_from_this());

R. P. Janaka

unread,
Aug 10, 2009, 5:40:46 AM8/10/09
to boost...@lists.boost.org
Yeah.. exactly this is what I wanted to know..

thank you.

2009/8/10 Björn Karlsson <Bjorn.K...@readsoft.com>

Björn Karlsson

unread,
Aug 10, 2009, 7:00:47 AM8/10/09
to boost...@lists.boost.org
Hello Igor,

> Why not:
> boost::static_pointer_cast<B>(shared_from_this());

Yes, inside B (as in the example), static_pointer_cast is the right choice. The same rules apply as for the corresponding C++ casts, so when downcasting, shared_pointer_cast should be used instead.

Cheers,
Bjorn Karlsson
www.skeletonsoftware.net

Frank Mori Hess

unread,
Aug 10, 2009, 8:52:00 AM8/10/09
to boost...@lists.boost.org
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Monday 10 August 2009, Björn Karlsson wrote:
>
> Don't let B inherit from enable_shared_from_this. You've already done that
> in A. So your question then becomes "how do I retrieve a shared_ptr<B> from
> this?". Here's how:
>
> boost::shared_dynamic_cast<B, A>(shared_from_this());

The shared_*_cast names are deprecated according to shared_ptr.hpp. They are
spelled *_pointer_cast now.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAkqAF/EACgkQ5vihyNWuA4VqFgCeO+XJhSihS1m+vxsDY0niQeEW
8LsAniPa51EYxc+dcwiI0ZdNndHsi9Wn
=KWJb
-----END PGP SIGNATURE-----

Björn Karlsson

unread,
Aug 10, 2009, 10:20:39 AM8/10/09
to boost...@lists.boost.org
Hello Frank,

> The shared_*_cast names are deprecated according to shared_ptr.hpp.
> They are spelled *_pointer_cast now.

You're right, thanks for the reminder. The rationale for this name change can be found in the smart pointer proposal, N1540:

"The cast operations were originally named shared_static_cast and shared_dynamic_cast in the Boost implementation, but it soon became clear that other smart pointer types can (and should) provide the same functionality, preferably in a generic manner, and the functions were renamed to *_pointer_cast to indicate wider applicability."

Cheers,
Bjorn Karlsson
www.skeletonsoftware.net

Reply all
Reply to author
Forward
0 new messages