Skip to main content
GameDev.net gamedev.net
🔒 Locked

casting this to a shared_ptr

Started by ruysch Feb 25, 2008 at 4:08 PM 12 replies 2.9k views
Original Post
ruysch
ruysch
Might be an easy one, but havent been able to find this using the search function. My problem is that I want to cast the this pointer into a boost::shared_ptr I have some resources, shaders, textures, surfaces, geometry. All inheriting from the same base resouce class. class D3DResource { public: D3DResource (ResourceType _resourceType) { ResourceAllocator::Get->addResouce (this); } }; typedef boost::shared_ptr ptr_d3d_resource; The problem is that the ResouceAllocators add method : void add (boost::shared_ptr resource); Any advice on howto go about this? Should I re-think the resouce system?
ruysch
ruysch
Might be but I am not sure how to use the boost::enable_shared_from_...

It doesnt seem to be sufficient to do

class CD3DResource : public boost::enable_shared_from_this {

};

Sorry tried the member function shared_from_this() and at least it compiles ;-)

Thanks alot!
rip-off
rip-off
Note: the below is incorrect.




Well, according to the example on the linked site, you would need to do this:
class CD3DResource : public boost::enable_shared_from_this<CD3DResource>{    D3DResource (ResourceType _resourceType)    {        ResourceAllocator::Get->addResouce(shared_from_this());    }};



[Edited by - rip-off on February 25, 2008 4:26:48 PM]
ruysch
ruysch
Unfortunatly I get an exception, inside the constructor of the first resouce I create, (and ofcourse all other resouces)

Microsoft C++ exception: boost::bad_weak_ptr at memory location

Seems like I get into the following code
in

shared_ptr<T const> shared_from_this() const {  shared_ptr<T const> p(_internal_weak_this);  BOOST_ASSERT(p.get() == this);  return p;}
rip-off
rip-off
From some simple experimentation of mine, you cannot use shared_from_this in the constructor, it appears not to be ready yet.

See here:
Quote:

There must exist at least one shared_ptr instance p that owns t.


This means that it cannot be used inside a constructor. Apologies, I didn't fully read the documentation. You could perhaps modify your application to account for this though.
ruysch
ruysch
Thanks anyhow. Should I use an other kind of smart pointer ?

The problem is that I could of course add the resource, but I might forget and therefor I prefer the constructor to do this for me. I could ofcourse skip boost totally but I think that would be ashame.
Ezbez
Ezbez
One possible way is to utilize a factory function or similar. Basically, it could just be a simple wrapper around the new, but would add in whatever capability you needed with boost:shared_ptr. If you're afraid of forgetting and using new directly, make the constructor private and the factory function a static member function of the class. That way, only the class can call the constructor directly.
ruysch
ruysch
I am not sure exactly how this translates to code ?
chairthrower
chairthrower
something like this
class A{        A() {  }public:        typedef shared_ptr< A> ptr;         typedef weak_ptr< A>   wptr;         wptr    self;         static ptr create()   { ptr p( new A); p->self = p; return p; }};int main(int argc, char **argv){         A::ptr a = A::create(); }
swiftcoder
swiftcoder
Another solution is to implement your own reference counting, and use boost::intrusive_ptr instead. I am forced to use this route because of my custom memory manager/debugger (which needs to track refcounts), but it also allows works around the shared_from_this problem.
Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]
ruysch
ruysch
class CD3DResource : public boost::enable_shared_from_this<CD3DResource> {public:  CD3DResource (ResourceType _resourceType);};CD3DResource::CD3DResource(ResourceType _resourceType) {  resourceType = _resourceType;	  // If I follow this in Visual Studio Debugger it throws an  // First-chance exception at .. in TestAllocator.exe: Microsoft C++         // exception: boost::bad_weak_ptr at memory location  CResourceAllocator::Get ()->add ( shared_from_this() );}class CFullScreenQuad : public CD3DResource {  CFullScreenQuad();public:		  typedef boost::shared_ptr<CFullScreenQuad> ptr;   typedef boost::weak_ptr<CFullScreenQuad>   wptr;   wptr self;   static ptr Create() {     ptr p( new CFullScreenQuad());     p->self = p;     return p;   }};


I seem to run into the same problem as before, at least I get a very similar exception. Anyhow its late so I will have to let it lie until tomorrow.
The exception gets thrown inside boost/shared_count.hpp


inline shared_count::shared_count( weak_count const & r ): pi_( r.pi_ )#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)        , id_(shared_count_id)#endif{    if( pi_ == 0 || !pi_->add_ref_lock() )    {        boost::throw_exception( boost::bad_weak_ptr() );    }}


[Edited by - ruysch on February 25, 2008 6:51:46 PM]
chairthrower
chairthrower
CD3DResource::CD3DResource(ResourceType _resourceType) {  resourceType = _resourceType;	  // If I follow this in Visual Studio Debugger it throws an  // First-chance exception at .. in TestAllocator.exe: Microsoft C++         // exception: boost::bad_weak_ptr at memory location  CResourceAllocator::Get ()->add ( shared_from_this() );}


I am not 100% certain but I firmly believe that you cannot create, and have available for use, a shared pointer at the time of construction of an object. If you were to seperate out the constructor code and instead place it in an init() method, and then were to call the init() directly in the static create() you would achieve the intended effect.

I agree the code becomes more messy (adding a seperate init()) - but in some ways it is more consistent with c++ when you consider the rules against calling virtual methods in constructors. Having a seperate init() means you are guaranteed the object is already completely constructed and you can rely on correct virtual function behaviour (as well as shared and weak pointers).

Btw the advantage of having the weak_ptr self is that you always have a handle that is tracked to the source of the original allocation available inside the class. This means you can pass yourself out (like passing this out) to other classes or event handlers in a memory safe manner.
ruysch
ruysch
Well I might do as you suggest. Let the constructor be private and have a static facory method from which I will also envoke init ();

Well its works out much better. And with a little brushing up it might be a clean solution after all.

[Edited by - ruysch on February 26, 2008 2:20:46 PM]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.