Performing static_cast<shared_ptr<base>*> on a shared_ptr<derived>*. Any guarantees?
I have taken over some code that boils down to
///begin code
#include <iostream>
#include
Pete Bartlett wrote:
I have taken over some code that boils down to
///begin code
#include <iostream> #include
struct base { int i; base(int i_):i(i_) {}> };
struct derived : base { derived(int i): base(i) {} };
int main() { boost::shared_ptr<derived> pd(new derived(5));
void* ptr_to_pd = &pd;
boost::shared_ptr<base>* ptr_to_pb = static_cast< boost::shared_ptr<base>* >(ptr_to_pd);
Why not: boost::shared_ptr<base> pb = static_pointer_cast<base>(pd);
std::cout << "\n" << pb->i ; //Prints 5
} ///End code
Now shared_ptr<B> and shared_ptr<A> are unrelated types, so IIUC there is no guarantee that this will work. Is that right? I know from the shared_ptr documentation that I should refactor in the direction of dynamic_ptr_cast (though complications not shown in the code above make that harder that). However for the time being this code appears to be working. Is that just a fluke? I.e. I am relying on the author of boost::shared_ptr and/or my compiler creators not to do something such that it doesn’t work. Is there the possibility that any memory could be deleted twice? Or I am worrying over nothing and in fact there is a reason why the above is safe?
See http://www.boost.org/libs/smart_ptr/shared_ptr.htm#functions. Jeff
Pete Bartlett wrote: ...
int main() { boost::shared_ptr<derived> pd(new derived(5)); void* ptr_to_pd = &pd; boost::shared_ptr<base>* ptr_to_pb = static_cast< boost::shared_ptr<base>* >(ptr_to_pd);
std::cout << "\n" << (**ptr_to_pb).i ; //Prints 5 }
The obvious question is why don't you just use boost::shared_ptr<base> pb( pd ); ?
Now shared_ptr<B> and shared_ptr<A> are unrelated types, so IIUC there is no guarantee that this will work. Is that right? I know from the shared_ptr documentation that I should refactor in the direction of dynamic_ptr_cast (though complications not shown in the code above make that harder that). However for the time being this code appears to be working. Is that just a fluke? I.e. I am relying on the author of boost::shared_ptr and/or my compiler creators not to do something such that it doesn't work.
Yes, you are relying on the author of boost::shared_ptr to not break this code. It so happens that boost::shared_ptr<X> is binary compatible with boost::shared_ptr<Y> whenever X* is binary compatible with Y*, but this isn't guaranteed for an arbitrary implementation of shared_ptr. Even so, this construct is inherently dangerous since it subverts the type system. You can assign to *ptr_to_pb a boost::shared_ptr<base> that doesn't point to a 'derived', but the portion of the code that holds pd will still think that its target is a 'derived' and may crash trying to access the nonexistent members of *pd.
participants (3)
-
Jeff Flinn
-
Pete Bartlett
-
Peter Dimov