smart pointer in an engine

Started by
8 comments, last by Ishraam 17 years, 9 months ago
Hi, On my way home I thought about something : having started to write an engine, I decided from the start to use boost::shared_ptr everywhere (class member attributes, function param, etc). 1. First of all is "everywhere" sensible ? 2. Are there places where smart pointers should be avoided (for some performance reason - maybe in the 3D renderer part ?) ? I'm especially concerned about Resource management (with let's say a ResourceManager containing a table (read "std::map") of (resourceID, resourceSmartPtr)). 3. I bet there would be problems when trying to affect a ResourcePtr to a TexturePtr (assume Texture inherits Resource). Right ?
Advertisement
1: 'Everywhere' isn't sensible - consider using boost::scoped_ptr, std::auto_ptr, or stack allocation for objects which aren't shared.

2: Also consider using boost:intrusive_ptr for speed critical regions if you really need reference counting.

3: No problems using shared_ptr with inheritance
Nitage :

1. Yep, of course :).

2. But boost::intrusive_ptr are not thread safe - which might be a problem for a ResourceLoader that process in a separate thread.

3. Oh, ok. Strange I 've just run into a problem (looks like reference counting went wrong...).
I have a class Material containing (let's say) a TexturePtr m_TexturePtr;
And when loading, I use ResourceLoader::Get which returns a ResourcePtr, and
m_TexturePtr = TexturePtr( static_cast<Texture*> ResourceLoader::Get("myTexture"));

I bet there's something wrong in there... no ?
A friend once said this:

C allows you to shoot yourself in the foot.
C++ allows you to reuse the bullets
With Boost, you're loaded for bear...
if the gun goes off, the entire foot is gone

The problem with smart pointers (and a lot of other cool stuff that Boost offers) is that used correctly, they're a great asset. If you mess up, though, the bugs are often much more difficult to track than a native C++ one (try tracking a memory-bug that passes through Boost::signals, for example).

These things should be used when you know WHY you're using them, and what their functions/limitations are. Before that, you're a danger to yourself, the environment and anyone inside the range of your newly loaded elephant rifle.

Allan
------------------------------ BOOMZAPTry our latest game, Jewels of Cleopatra
Don't worry noone's live will be endangered :). I love my feet & they love me.

I'm not writing code for commercial reasons.

I'm __asking__ since I'm in the process of __learning__. Note that I would definitely not ask if I was a C++/Boost god, neh,Odin ;).

Of course I could stick to C, or basic C++. But I woudn't even have ever got to learn these if I hadn't __try__ to learn.

And I don't know for you, but I MUST make mistakes when learning, anyway.
But sure, I do read the docs - I simply forget what I read too quick sometimes... :p
Quote:
3. Oh, ok. Strange I 've just run into a problem (looks like reference counting went wrong...).
I have a class Material containing (let's say) a TexturePtr m_TexturePtr;
And when loading, I use ResourceLoader::Get which returns a ResourcePtr, and
m_TexturePtr = TexturePtr( static_cast<Texture*> ResourceLoader::Get("myTexture"));


Which of those pointers are T* and which ones are boost::shared_ptr<T>?
Ho sorry, silly me. (tired)
Ho mistake moreover :|
Let me rewrite :

m_TexturePtr = TexturePtr( static_cast<Texture*> ((ResourceLoader::Get("myTexture")).get());

The only T* is the one I get through the usual shared_ptr<..>::get() func.

So to make things clear

class Resource {...};
class Texture : public Resource {...};

typedef boost::shared_ptr<Resource> ResourcePtr;
typedef boost::shared_ptr<Texture> TexutrePtr;

class ResourceLoader
{
...
std::map< id, ResourcePtr> m_table;
...
ResourcePtr Get(id) const;
};

Every resource loaded goes into the ResourceLoader::m_table, e.g. on load a TexturePtr will be cast as a ResourcePtr before being appended to the m_table.

My problem is when I when to Get() the TexturePtr from the m_table, and want to assign it to a Material::TexturePtr for exemple : I will have to assign (operator=)
a shared_ptr<Resource> (which is in fact a shared_ptr<Texture>)
to another already created (on object construction) shared_ptr<Texture>.

(In other words : shared_ptr<Texture> = shared_ptr<Texture> (static_cast<Texture*> (shared_ptr<Resource>.get())); -- ugly neh ?)
That isn't a problem with boost::shared_ptr, it's a problem with your code.

You are trying to convert a pointer to a resource(base class) into a pointer to a texture(derived class) - that's an unsafe conversion, as not all resources are textures - if you aren't to far in you should consider changing your design.

To fix the code as it is:
m_TexturePtr = TexturePtr( boost::dynamic_pointer_cast<Texture>(ResourceLoader::Get("myTexture")) );//the same with normal pointersTexture* ptr = dynamic_cast<Texture*>(ResourceLoader::Get("myTexture"));
hmmm, I was about to post what Nitage did, good job I scrolled down on look [grin]

On the container front, I'm currently working on a resource loader system the output of my thoughts can be found in my journal, you might want to have a read [smile]
@ Nitage :
I'm not too far in my design, no :p.
I didn't know about boost::dynamic_pointer_cast so I'll give a try at your first proposition.

BTW, I should have typde 'dynamic_cast' instead of 'static_cast' - I spit it from the top of my head, without much reflexion I recognize.

@ phantom:
I'll have a look at your journal


Thanks!

This topic is closed to new replies.

Advertisement