
Philippe Cayouette <pcayouette@spoluck.ca> writes:
On 10-11-28 03:02 PM, Ansel Sermersheim wrote:
In my solution, my enable_shared_from_polymorphic<T> class is just a shim that inherits virtually from enable_shared_from_polymorphic_base, which is not a template type. The base class holds a weak pointer, which can be dynamic_pointer_cast by the child class when needed.
Interesting idea, you resolve the problem of multiple inheritance with virtual inheritance. Having a single internal weak_ptr is surely a better idea than having a lot of them.
This allows your example to work as expected by merely inheriting from enable_shared_from_polymorphic<T> rather than enable_shared_from_this<T>.
Did you tried your code on GCC? I just applied your patch and I think I am encountering the same problem as my example: on GCC, the function sp_enable_shared_from_this that is called is the one with the variable arguments (...), since the compiler cannot be sure of the value of T in the expression enable_shared_from_polymorphic< T > (it might be Base1 or Base2). On VS2005, the compiler chooses Base1 (in the original example) and thus, the pe->_internal_accept_owner function is called on the unique enable_shared_from_polymorphic_base and everything works (I guess, I didn't try).
This is rather puzzling. I do develop on GCC, I tested with: bash$ g++ --version g++ (Debian 4.4.5-6) 4.4.5 Copyright (C) 2010 Free Software Foundation, Inc. However, your idea of having the _internal_accept_owner function take an enable_shared_from_polymorphic base makes perfect sense, and I have made that change. Hopefully that builds more happily for you.
If anyone is interested in the code, it can be found at:
http://208.106.110.44/~ansel/boost/enable_shared_from_polymorphic.patch
This patch is against the current SVN version of boost.
The pro of this method is that the class can be used identically to the way that enable_shared_from_this is used. A downside is that any class deriving from enable_shared_from_polymorphic<T> becomes polymorphic and incurs all the cost thereof.
IMHO, I think the biggest downside of your method is the usage of dynamic_pointer_cast, not the polymorphic costs. In fact, dynamic casts are non-deterministic and need RTTI, which is not always enabled depending on the environment (e.g. VxWorks 653 with cert). Real-time applications often disable RTTI to make sure they stay deterministic.
Very good point, and one I often miss since most projects I work on use RTTI extensively.
This cost could potentially be mitigated if these classes used static_pointer_cast instead of dynamic_pointer_cast. However, I am not familiar enough with the appropriate areas of the C++ standard to be sure that would work in cases of multiple inheritance, precisely when these classes are useful.
If you manage to make this work with static_pointer_cast instead of dynamic_pointer_cast, it would be the perfect solution to me... but I am not sure it is possible.
After mulling this over for some time, I _think_ I have come up with a solution that mitigates all these problems. I have a new patch up, at the same URL. In order to make this mechanism work, I had to add a new constructor to boost::shared_ptr<T>, which I am loath to do. Given that downside the patch appears to work properly. It also adds a free function boost::shared_from<T>(T*) which returns a boost::shared_ptr<T>. The only cast that occurs in this code is a static_cast that downcasts from enable_shared_from_polymorphic<T> to T. I have read the relevant portions of the standard several times and I beleive this is valid, but I would definitely be curious if wiser heads agree with my reading. I would be very curious to hear if this new patch compiles successfully on your system. Thanks for your feedback, Ansel