Casting boost weak_ptr<T> to my class

Started by
7 comments, last by SiCrane 12 years ago
Hello,

I have a GameObjectFactory which creates/destroys a GameObject with the following methods:
mMemoryMgr is a custom memory allocation/deallocation module




template <class T>
inline static void DestroyObject(T* obj)
{

mMemoryMgr->Deallocate(obj);
}

// T is supposed to be a derived class of GameObject

template <class T>
inline boost::shared_ptr<T> CreateObject()
{
boost::shared_ptr<T> sPtr((T*) mMemoryMgr->Allocate(sizeof(T)),DestroyObject<T> );

// get a weak_ptr from shared_ptr and cast its object to gameobject
boost::weak_ptr<GameObject> wPtr = boost::static_pointer_cast<boost::shared_ptr<GameObject>>(sPtr);

// add it to some container of weak_ptr<gameobject>
mObject.push_back(wPtr);


return sPtr;
}


I have the following problems though with my design;

1. I get the following errors when trying to cast the shared_ptr<T> to weak_ptr<GameObject>:

Error 2 error C2440: 'initializing' : cannot convert from 'boost::shared_ptr<T>' to 'boost::weak_ptr<T>'
Why is this?

2. I'm new to template programming; Is there any way to 'enforce' in compile time in CreateObject() that T is derived from GameObject through a predicate or something?
such as template <class T where T is derived from GameObject>...

Thanks
Advertisement
1) boost::shared_pointer_cast<>'s template argument should be the type parameter of the shared pointer type, not the shared pointer's type. In other words boost::static_pointer_cast<gameobject>(sPtr); instead of boost::static_pointer_cast<boost::shared_ptr<GameObject>>(sPtr). However, in this case, the cast isn't necessary. You can construct a weak_ptr to a base class directly from a shared_ptr to a derived class.

2) You can't apply constraints of that sort with C++'s templates. In this case, if you try using the template with a class that doesn't have an implicit conversion from it's pointer type to GameObject * then you'll get a compiler error.

Also, as mentioned in your previous thread, you're still passing an unconstructed object to the shared_ptr. Further, your clean up function doesn't call the destructor when all the shared_ptrs go out of scope.
1, I'm not familiar with Boost smart pointers. But I think you need to construct a new weak pointer from T?
2, There is type traits library in Boost, and there is is_base_of. You can use it to check if GameObject is base of T. If you want compile time enforce, there is enable_if in Boost. See using enable_if here,
http://www.boost.org/doc/libs/1_49_0/libs/utility/enable_if.html

https://www.kbasm.com -- My personal website

https://github.com/wqking/eventpp  eventpp -- C++ library for event dispatcher and callback list

https://github.com/cpgf/cpgf  cpgf library -- free C++ open source library for reflection, serialization, script binding, callbacks, and meta data for OpenGL Box2D, SFML and Irrlicht.


1) boost::shared_pointer_cast<>'s template argument should be the type parameter of the shared pointer type, not the shared pointer's type. In other words boost::static_pointer_cast<gameobject>(sPtr); instead of boost::static_pointer_cast<boost::shared_ptr<GameObject>>(sPtr). However, in this case, the cast isn't necessary. You can construct a weak_ptr to a base class directly from a shared_ptr to a derived class.

2) You can't apply constraints of that sort with C++'s templates. In this case, if you try using the template with a class that doesn't have an implicit conversion from it's pointer type to GameObject * then you'll get a compiler error.

Also, as mentioned in your previous thread, you're still passing an unconstructed object to the shared_ptr. Further, your clean up function doesn't call the destructor when all the shared_ptrs go out of scope.


Thanks, I missed that. It works nicely.
There is one thing that boogles me though; how do I supply constructor arguments to my GameObject baseclass? When I call placement new with T(), it then also calls GameObjects constructor too right, but if I pass arguments to T() then the derived class gets those arguments passed to it, rather than my baseclass?

Edit: For example, I want to pass the GameObject its ID and I don't want to expose a public method to do it
A derived class can call a base class constructor via the member initialization list. Ex:

struct Base {
Base(int id) {
// stuff
}
};

struct Derived : Base {
Derived(int id) : Base(id) {
// stuff
}
};

A derived class can call a base class constructor via the member initialization list. Ex:

struct Base {
Base(int id) {
// stuff
}
};

struct Derived : Base {
Derived(int id) : Base(id) {
// stuff
}
};



Aye, but that means each derived class has to manually construct it like that. Is there any way to automate and hide this process from the derived classes?

Edit: how the 'friend' classes work? I've heard the concept but havn't found any good example use of it - maybe thats a good idea?
If you want to pass an argument to a base class constructor, then a derived class constructor has to do it. That's just how C++ works. Friending another class just gives that other class access to private and protected members of the first class. It doesn't affect construction in any way.

If you want to pass an argument to a base class constructor, then a derived class constructor has to do it. That's just how C++ works. Friending another class just gives that other class access to private and protected members of the first class. It doesn't affect construction in any way.


I thought GameObjectFactory could friend the GameObject so it could set the ID etc without having the GameObject revealing a public method for it
Other way around. GameObject could friend GameObjectFactory if it wants to allow GameObjectFactory to access non-public members of GameObject.

This topic is closed to new replies.

Advertisement