std::map is driving me insane!

Started by
30 comments, last by swinchen 18 years, 7 months ago
hmmm, I could always store the reference count in the map....

typedef std::map<std::string, std::pair<int, SawEngine::CTexture*> > t_textureMap;

Maybe I am making this more complicated than I need too.

Advertisement
I am not saying that your current implementation is slow. I am saying that shared_ptr implementation is probably more efficient (simply because dozens of very good developers put active efforts into that code with explicit requirement to make it fast).
Oh I know. I am just toying around with other ways of doing it. There is a feature I think I would like to add eventually.. let me explain.

When no objects are referencing a texture, one option would be to free that texture. Well if that texture gets used again then it needs to get loaded off the disk. What if the texture manager simply puts the texture into a another map of textures that can be reclaimed? That way if another object looks for this texture that is no longer being used it can check the "reclaim map" first? Of course you would have to provide a method like CTextureMgr::purge(); or something like to actually free up the unused textures.

It seems like this would be difficult with smart pointers.

This might (probably isn't) the best way to handle this, but I am pretty new to this... so I am still learning.
I couldn't see this mentioned anywhere, so I'll say it: You should have 'glDeleteTextures(1,&(texPtr->texID))' only in the destructor of your CTexture class. It's a very bad practice to access the internals of an object like this outside of the class.

And as others have said, boost smart pointer would have saved you a lot of trouble here. You wouldn't have even had to have written a destructor for CTextureMgr as CTextures in m_textures would have been deleted automagically.
Quote:What if the texture manager simply puts the texture into a another map of textures that can be reclaimed?

You can query the number of references to an object pointed through boost shared_ptr. So if you keep textures in a map in the manager, then just go through the map once a while and see which textures are referenced only once.
Ok, so here is my revised CTexture.

class CTexture{  private:    GLuint m_textureID;    GLuint m_width, m_height, m_bytesPerPixel;    public:    CTexture() : m_textureID(0), m_width(0), m_height(0), m_bytesPerPixel(0) {}    ~CTexture()    {      if ( glIsTexture(m_textureID) )      glDeleteTextures(1, &m_textureID);      return;    }        inline GLuint getWidth() { return m_width; }    inline GLuint getHeight() { return m_height; }    inline GLuint getBytesPerPixel() { return m_bytesPerPixel; }        inline void setWidth(GLuint p_width) { m_width = p_width; }    inline void setHeight(GLuint p_height) { m_height = p_height; }    inline void setBytesPerPixel(GLuint p_bytesPerPixel)     {       m_bytesPerPixel = p_bytesPerPixel;    }};


It probably makes sense to have the CTextureMgr to load the image, and assign the member variables. I was toying with having a "loadFromFile" function in CTexture.

What do you think? load the file in the texture manager, or in the texture?
You should also take a look at boost's invasive smart pointer. This has the same advantages as a shared pointer but allows you to store the reference count in the object itself. This is closer to the system you already have set up.

A problem I've had in the past with shared pointers is the difficulty of a class handing out pointers to itself. You can't do something like return shared_ptr<thisClass>(*this); because it creates a separate reference count. Using an invasive pointer alleviates the complexities of storing a weak pointer from the original shared pointer.
Quote:Original post by MidoriKid
A problem I've had in the past with shared pointers is the difficulty of a class handing out pointers to itself.

Yes!! This is my single biggest gripe with shared_ptr, if you don't count the whole cyclic reference business [smile] I'm still looking for a good solution.
Quote:Original post by MidoriKid
Using an invasive pointer alleviates the complexities of storing a weak pointer from the original shared pointer.

How did you solve the 'this' problem with invasive pointers again?
intrusive_ptr This is the one you are talking about correct?

The whole weak_ptr, and shared_ptr thing is really throwing me. It looks like an intrusive_ptr might be the best bet for me, or maybe my:

typedef std::map<std::string, std::pair<int, CTexture*> > t_textureMap;

idea. I think that would work pretty well actually.

Oh .. one more question. Is there a way to return a pointer (smart or other wise) that doesnt allow the returnee to modify the data structure?

Thanks.
To create an object using a shared_ptr the "proper" way:
shared_ptr<myClass> myPointer(new myClass);
This creates a reference count outside of the class. Any time the myPointer is copied the reference count is incremented. If the reference count drops to zero the object is deleted. The problem here is more than one reference count can exist if you're not careful. If you try to hand out a shared pointer from within the class you might try to do it like this:
return shared_ptr<myClass>(this);
This would be very unfortunate because it creates a reference count separate from when new was called to create this object. Now as soon as the pointer you returned goes out of scope (assuming it was not copied) the object will be deleted no matter how many references the original pointer holds.

One work around for this is to make the constructor for the object private (and thus inaccessible) and only create objects through a static factory function that returns a shared_ptr. This allows the factory function to store a weak pointer in the object referencing itself. This is a valid option especially if you want to enforce the use of shared_ptr.

Of course, you already know all this. The way around the whole mess is to use intrusive_ptr. This type of smart pointer acts just like a shared_ptr but stores the reference count in the object itself preventing the possibility of two separate reference counts existing for the same object. For an object to hand out a pointer to itself it simply creates a new intrusive_ptr:
return intrusive_ptr<myClass>(this);
The object's reference count is automatically incremented.

This type of smart pointer does have at least one disadvantage, however. You must define intrusive_ptr_add_ref and intrusive_ptr_release functions in the host class. See Smart Pointers to boost your code for an example.

edit: Removed dereferenced *this. Those constructors take pointers.

This topic is closed to new replies.

Advertisement