Dynamic and reinterpret casting of SharedPtr

What it says on the tin: a place to discuss proposed new features.
Post Reply
User avatar
vitefalcon
Orc
Posts: 438
Joined: Tue Sep 18, 2007 5:28 pm
Location: Seattle, USA
x 13

Dynamic and reinterpret casting of SharedPtr

Post by vitefalcon »

Hi,

Just when I was working with Ogre::SharedPtr<T> I found that it would be very useful if SharedPtr's could be dynamically cast'ed.
For e.g.:

Code: Select all

Ogre::SharedPtr<BaseClass> ptr(new DerivedClass);
//... later in another function
Ogre::SharedPtr<Derived> derived_ptr = Ogre::SharedPtr::DynamicCast<Derived>(ptr);
There is two major barriers with the current code and that is SharedPtr<Derived> cannot access SharedPtr<BaseClass> protected members, because they're considered as two separate classes according the compiler and the second problem is that dynamic casting is not done to convert the BaseClass pointer to DerivedClass pointer.

Making certain changes to the SharedPtr class, I believe can make this possible. And this is not a huge change. And what I'm proposing is not a new thing. It's something done in boost::shared_ptr. Here are the list of changes I was thinking would make that possible

1. Make a private 'dummy' structure in SharedPtr to indicate that a dynamic cast request is being made when constructing
2. Make a private constructor that would accept an instance of the 'dummy' structure and that constructor that do the dynamic_cast operation.
3. Make template<typename Y> SharedPtr a friend class so that any type of SharedPtr instance can access the protected members.

The change is shown below...

Code: Select all

template <typename T>
class SharedPtr
{
private:
	// Declaring that 'any' type of SharedPtr is friend of any other type
	template<typename Y> friend class SharedPtr;
	// The dummy structure that is used to make the call to the constructor that will do dynamic casting
	struct DynamicCastRequest{};
	// The constructor that will do dynamic casting of the pointer stored in the other SharedPtr type.
	template<typename Y>SharedPtr(const SharedPtr<Y>& r, const DynamicCastRequest& d)
		: pRep(0), pUseCount(0), useFreeMethod(SPFM_DELETE)
	{
		// lock & copy other mutex pointer
		OGRE_SET_AUTO_SHARED_MUTEX_NULL
		OGRE_MUTEX_CONDITIONAL(r.OGRE_AUTO_MUTEX_NAME)
		// This is now possible because SharedPtr<Y> is a friend class of SharedPtr<T> and viceversa
		pRep = dynamic_cast<T*>(r.pRep);
		if(pRep)
		{
			pUseCount = r.pUseCount;
		}
		useFreeMethod = r.useFreeMethod;
		if(pUseCount)
		{
			++(*pUseCount);
		}
	}
public:
	// .... rest of the class code...
	template<typename Y>
	static SharedPtr<T> DynamicCast(const SharedPtr<Y>& r)
	{
		return SharedPtr<T>(r, DynamicCastRequest());
	}
	// ... remaining class code...
};
I'm not entirely sure if this piece of code is portable. But I believe it will be useful and maybe more tweaks can be done to make this code better. The same can be done to perform reinterpret_cast.
Image
User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Re: Dynamic and reinterpret casting of SharedPtr

Post by xavier »

Unless you have code that is asserting shared ownership of a SharedPtr, you probably shouldn't be using SharedPtr directly, and instead taking the naked pointer you get from SharedPtr.get() (or whatever the Ogre::SharedPtr equivalent is, if it's not the same as the Boost shared_ptr). This not only lets you cast the naked pointer to whatever you like, it declaratively annotates that you are only taking a weak reference to the pointer.
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.
User avatar
vitefalcon
Orc
Posts: 438
Joined: Tue Sep 18, 2007 5:28 pm
Location: Seattle, USA
x 13

Re: Dynamic and reinterpret casting of SharedPtr

Post by vitefalcon »

I was thinking more of the lines like, as a very crude example, you have a certain ResourcePtr which happens to be a MeshPtr and you need that MeshPtr to be passed into an Actor class. I believe there is no way to 'Dynamic Cast' a given ResourcePtr to a MeshPtr. Wouldn't this help achieve that where it's required that the ownership is shared? Correct me if I'm wrong.
Image
User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Re: Dynamic and reinterpret casting of SharedPtr

Post by xavier »

It depends on whether the Actor class needs to own the MeshPtr, or is it just "borrowing" it -- if the latter, use naked pointers. Usually, the Actor would have an Entity contained, wouldn't it? And not a MeshPtr directly?
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.
User avatar
vitefalcon
Orc
Posts: 438
Joined: Tue Sep 18, 2007 5:28 pm
Location: Seattle, USA
x 13

Re: Dynamic and reinterpret casting of SharedPtr

Post by vitefalcon »

I was just trying to point out a crude example where one would need to dynamic cast a shared pointer for the reason of keeping ownership of it. At the moment there is no way with SharedPtr to do that. :)
But yea, Actor class would have Entity in it :P
Image
User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Re: Dynamic and reinterpret casting of SharedPtr

Post by xavier »

Yeah, if you do need to share ownership then that's an issue. I'm trying to think if boost::shared_ptr supports such a cast or not; all I know is that on the codebase at work, when I tried to copy-ctor a derived boost::shared_ptr from a base one, it segfaulted the compiler. ;)
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.
User avatar
vitefalcon
Orc
Posts: 438
Joined: Tue Sep 18, 2007 5:28 pm
Location: Seattle, USA
x 13

Re: Dynamic and reinterpret casting of SharedPtr

Post by vitefalcon »

Actually this concept was taken from boost::shared_ptr :P ... boost has something like

Code: Select all

boost::shared_ptr<T> boost::shared_dynamic_cast<T>(const boost::shared_ptr<Y>& ptr)
// USAGE
boost::shared_ptr<DerivedType> derived_ptr = boost::shared_dynamic_cast<DerivedType>(base_ptr);
The method is similar. In the way i proposed you don't need to specify a type because the dynamic cast function will be a static function of the class to which the other SharedPtr needs to be dynamically casted.
Image
Post Reply