Sunday, 18 March 2012

Error passing 'const...' discards qualifiers C++

Okay so I'm making steady progress on a simple game engine which I'm going to call the Assassin Engine 'cos it sounds ace.  As I'm getting deeper into C++ programming I am finding all the lovely quirks of the language.  Quirk number 1 - Scott Meyers is a god when it comes to C++.  This puts me in a tricky position because I'm an atheist.  So I can either deny that Effective C++ - 55 Ways... is a book of almost divine scripture or I can be pragmatic and say there is useful stuff in there.

Tbh I haven't finished reading it yet.  Each item makes so much sense that to absorb it fully takes time.  If you were to run a concordance on my code you would now find that the 'const' keyword outnumbers everything else by about 5 to 1.  This is from the first few pages in the book.

Quirk number 2 - Turns out that pointers never really were pointers in C++ which comes as an enormous surprise to me.  I have now accepted the fact that I was a dirty C with Objects hack and that my obsession with the asterisk was naive.  Now we work with unique pointers and shared pointers.

All this constness and these clever pointers does get me into a little bit of a tizz every now and again as I'm adjusting to new paradigms of programming.  Here is a prime example:

I am creating a TextureManager that basically holds a list (map) of textures that you can call into with an id.  The idea being that you just add the texture id to an object and that gives you access to render the texture etc. from that object or something like that anyway.  I am storing the textures in a map of <int, TexturePtr> the int being the id and the TexturePtr being a shared_ptr to the texture.  Apparently unique_ptr should now be compatible with maps but I don't think gcc have got round to implementing it yet.


So I overloaded the [] operator with - 

const ASTexturePtr operator[](const int position) const { return TextureMap[position]); }

and got into a heap of trouble.  Basically I was getting a very extensive error with lots of chevrons and maps which basically said you have an error which discards qualifiers in C++.

It took me a little bit of research to figure out what it actually meant but the short end of it is that I was using a non-const function in a const-function.  So in theory dropping the constness of the function should make it compile?


const ASTexturePtr operator[](const int position) { return TextureMap[position]); } 


It did!  But I did want this to be a const function, it shouldn't update the internal state of the object so satisfies the scenario for bitwise constness so why shouldn't it be const?  I can only surmise that when you use the [] operator on a map, because you can update that entry with that operator it is not a const function.  So for example you can do -

MyMap["Apple"] = "Orange";

Thus changing the internal state of the object and failing all tests (bitwise and logical) for constness. So the way around this is to provide a function which will access the map by an id and is a const function.  Something like

ASTexturePtr getTextureAtId(const int p_Id) const
{
  TextureMgrMapEntry::const_iterator it = TextureList.find(p_Id);

        if(it != TextureList.end())
        {
            return it->second;
        }
        return ASTexturePtr();
};


and then use that in your overloaded operator:


const ASTexturePtr operator[](const int position) const { return getTextureAtId(position); }

then you get compilation.  Excellent!

The great thing about C++ is that coding normally means a thousand of these little problems and that normally they are created thorough a lack of understanding of the language.  It is these types of things that are headed off at the pass by good design and robust coding style.  I'm not there yet but I'm getting there :)