Can you multiply inherit from objects that inherit from
enable_shared_from_this? It seems not. My program compiled on MSVC.NET
"crashes" due to shared_from_this throwing boost::bad_weak_ptr.
Originally when I started using shared_ptr I wanted to have an ability
to obtain a shared_ptr to this since my objects sometimes register
themselves.
The way I do it now is like this:
static sptr create() {
sptr ret( new Object() );
ret->setThisPtr( ret );
return ret;
}
However it is very easy to forget which classes you inherit from that
force you to call setThisPtr. A good use of the assert statement helps
but I'd rather not do this. The problem is that I use multiple
inheritance in one place:
static sptr create() {
sptr ret( new ComplexObject() );
ret->BaseA::setThisPtr( ret );
ret->BaseB::setThisPtr( ret );
return ret;
}
I thought I'd use enable_shared_from_this but as I said it crashes. The
following program as tested on MSVC.NET throws boost::bad_weak_ptr then
the line "Base2::sptr b2 = c->Base2::getThis();" is executed.
#include <iostream>
#include
Jason Winnebeck wrote:
Can you multiply inherit from objects that inherit from enable_shared_from_this? It seems not. My program compiled on MSVC.NET "crashes" due to shared_from_this throwing boost::bad_weak_ptr.
[...]
class Base1 : public SharedThis<Base1> {
[...]
class Base2 : public SharedThis<Base2> {
[...]
class Child : public Base1, public Base2 {
No, you can't do that. Multiple enable_shared_from_this<> bases are not supported, there is no way to enumerate them. The typical enable_shared_from_this use would look like: class Base1; // abstract class Base2; // abstract class Child: public Base1, public Base2, public enable_shared_from_this<Child>; Multiple inheritance from concrete classes is just problematic, in more ways that just enable_shared_from_this not working. :-) BTW, if you have a static creation function, and it seems that you do: static sptr create() { return sptr( new Base1() ); } consider whether you only need a "shared_ptr from this" at construction time, and if so, simply perform the necessary registration in create(): static sptr create() { sptr this_( new Base1() ); register(this_); return this_; } In general, enable_shared_from_this is to be avoided. You only need it in some rare cases.
Peter Dimov wrote:
class Child : public Base1, public Base2 {
No, you can't do that. Multiple enable_shared_from_this<> bases are not supported, there is no way to enumerate them.
Don't know if I've missed part of this thread, but couldn't you use virtual inheritance here? Russell
Russell Hind wrote:
Peter Dimov wrote:
class Child : public Base1, public Base2 {
No, you can't do that. Multiple enable_shared_from_this<> bases are not supported, there is no way to enumerate them.
Don't know if I've missed part of this thread, but couldn't you use virtual inheritance here?
That could be an idea, but I've never used it in practice. Virtual inheritance has always been solely an academic thing. That's probably going to get pretty complicated, and one I'd think would have to seriously question a design that invovled virtual inheritance. I might try it out just out of curiousity to see if I can get it to work. Maybe if it works it might be useful if I really want to do it. I've also always have wondered how virtual inheritance works under the hood, it might be a good time to look at that. Jason
Peter Dimov wrote:
Multiple inheritance from concrete classes is just problematic, in more ways that just enable_shared_from_this not working. :-)
Yes I know that ;). This is the only time I've done it and perhaps I've made a mistake. I have a class Thread, so objects that are Threads inherit from Thread and something else sometimes. I probably should have considered doing something like the Runnable interface from Java, espically since I modeled my API similarly to Java's Thread class. What I do with shared_ptr, is that I have to enforce a "base" reference, so there is a map of threads where the references are stored. This keeps the Thread instance alive while the Thread is running. Thus when a Thread starts, its shared_ptr is needed.
static sptr create() { sptr this_( new Base1() ); register(this_); return this_; }
I do keep that in mind. I have done that in some places.
In general, enable_shared_from_this is to be avoided. You only need it in some rare cases.
Hmm I thought it would be a good thing to have a lot of the classes provide a "getPointer" method. Well actually I just realized that is pretty flat out moronic, because you need a shared_ptr to call the get function, unless you are given a reference (which does happen in the listeners as you suggested earlier). Jason
I tried using enable_shared_from_this with virtual inheritance, just to see if it would work. I couldn't get it to work. The first barrier is that enable_shared_from_this is a templated class, and from what I understand is that two template instantiations of a class are two entirely different classes, so I didn't even try to use virtual on that. Instead I tried to make the SharedThis class non-templated, and virtually inherit from that. However it didn't work, because of pointer casting issues. I'm not sure if this is what caused my errors, but I heard that you can't downcast from a virtual base class * to a concrete class without dynamic_cast. Jason
Jason Winnebeck wrote:
I tried using enable_shared_from_this with virtual inheritance, just to see if it would work. I couldn't get it to work. The first barrier is that enable_shared_from_this is a templated class, and from what I understand is that two template instantiations of a class are two entirely different classes, so I didn't even try to use virtual on that.
Sorry, I completely missed that enable_shared_from_this was a template class. Yes in that case it won't work unless possibly you did something like this class TheBase : public enable_shared_from_this<TheBase> { }; class Base1 : virtual public TheBase { }; class Base2 : virtual public TheBase { }; class MyClass : public Base1, public Base2 { }; But then you may need dynamic_casts somewhere to get the actual interface pointer you required later so don't know if that will be possible. Thanks Russell
No Russel I just tried that, it won't work. That's sort of how my code was. Your TheBase class is my SharedThis class from eariler example, and I had non-templated. It wouldn't compile because the enable_shared_from_this couldn't cast some pointer. Jason Russell Hind wrote:
Jason Winnebeck wrote:
I tried using enable_shared_from_this with virtual inheritance, just to see if it would work. I couldn't get it to work. The first barrier is that enable_shared_from_this is a templated class, and from what I understand is that two template instantiations of a class are two entirely different classes, so I didn't even try to use virtual on that.
Sorry, I completely missed that enable_shared_from_this was a template class. Yes in that case it won't work unless possibly you did something like this
class TheBase : public enable_shared_from_this<TheBase> { };
class Base1 : virtual public TheBase { };
class Base2 : virtual public TheBase { };
class MyClass : public Base1, public Base2 { };
But then you may need dynamic_casts somewhere to get the actual interface pointer you required later so don't know if that will be possible.
Thanks
Russell
Jason Winnebeck wrote:
Instead I tried to make the SharedThis class non-templated, and virtually inherit from that. However it didn't work, because of pointer casting issues. I'm not sure if this is what caused my errors, but I heard that you can't downcast from a virtual base class * to a concrete class without dynamic_cast.
That's correct. A virtual base class's offset can vary at runtime.
participants (3)
-
Jason Winnebeck
-
Peter Dimov
-
Russell Hind