.NET Forum / Languages / Managed C++ / December 2004
Why does reading from a std::map not considered const?
|
|
Thread rating:  |
Peteroid - 29 Nov 2004 04:16 GMT Why does reading a member of a std::map not considered const? For example:
class My_Class { int Get_Map_Value( int index ) const // ** error ** not considered const!!! { return m_Map[index] ; // note that m_Map is not changed, only read from } std::map<int,int> m_Map ; } ;
This really reeks havoc when to try to use const for its intended purpose...
[==Peteroid==]
PS - I'm using MS VC++.NET and creating a Managed C++ application, if that matters...
Doug Harrison [MVP] - 29 Nov 2004 04:46 GMT >Why does reading a member of a std::map not considered const? For example: > [quoted text clipped - 15 lines] >PS - I'm using MS VC++.NET and creating a Managed C++ application, if that >matters... If the key isn't already present in the map, map::operator[] will create a new (K,V) pair and store it in the map, returning the V part by reference. (Use of this operator requires the mapped_type be default-constructible.)
You can avoid this behavior by using map::find, though your function as specified above will either have to return a default value or throw an exception if that function returns end().
 Signature Doug Harrison Microsoft MVP - Visual C++
Peteroid - 29 Nov 2004 12:25 GMT So, if I get you right, using operator[] on a std::map isn't const because of the POSSIBILITY it might give be given a key not already in the map. Thus, even if my code insures I won't ever ask for an entry for which a key doesn't already exist, it can't be declared const since I might not write good code in this regard.
I believe I now understand, but feel it should have been the case that operator[] was designed to allow const and to just cause an error if a request for an entry where no key existed was asked for, and force people to check on existence using the count() method (which returns 0 if the entry doesn't exist and 1 if it does). That is, treat it much like trying to access an array element that is out of bounds...
Thanks Doug!
[==Peteroid==]
> >Why does reading a member of a std::map not considered const? For example: > > [quoted text clipped - 23 lines] > specified above will either have to return a default value or throw an > exception if that function returns end(). Bret Pehrson - 29 Nov 2004 16:09 GMT > So, if I get you right, using operator[] on a std::map isn't const because > of the POSSIBILITY it might give be given a key not already in the map. [quoted text clipped - 8 lines] > doesn't exist and 1 if it does). That is, treat it much like trying to > access an array element that is out of bounds... const is an abortion in C++.
In theory, it sounds like a good idea. In practice, it just doesn't work.
Peteroid - 30 Nov 2004 04:55 GMT > const is an abortion in C++. > In theory, it sounds like a good idea. > In practice, it just doesn't work. At the risk of starting a 'religous war', const is one of those 'road blocks' we throw into our own programming path to make sure we don't accidentally fall off a cliff. Another such road block is 'private'. You could always define everything in a class to be 'public'. In fact, any code that works will still work if 'private' is replaced by 'protected' or 'public'. However, 'private' prevents outside forces from changing such variables without going through the mechanisms provided by the class. This encapsulates the class so that it will perform more like a self-contained object than merely a convenient and organizational combinantion of code and data.
In the case of 'const' this allows programmers to insure that a class method does not actually change anything in the class. In effect, it makes sure that those methods you intend to be 'read-only' in nature with respect to the class, are indeed, living up to that promise. It therefore acts as a way of programming with a particualr style or mindset (a paradigm if you will), to help find problems in dis-functioning code (via visual elimination of methods that couldn't possibly change class members), and as a guard dog to prevent conception errors at compile time.
I tend to use 'const' whenever I can. But, like I occasional must demote (promote? guess it depends on your pov) 'private' to 'protected' (like when it is faster and/or makes more sense for a child to have direct access than to have to go through a 'property' method of the parent), sometimes I find I must remove the 'const', simply because I realize it only changes an un-important part of the class (such as a temporary convenience variable), or as this thread is about, I'm using a standard template library container which looks like it should act const, but in fact is not.
And, as you can see, I'm more than happy to construct run-on sentences to make my points...lol
[==Peteroid==]
Bret Pehrson - 30 Nov 2004 16:28 GMT > > const is an abortion in C++. > > In theory, it sounds like a good idea. [quoted text clipped - 3 lines] > blocks' we throw into our own programming path to make sure we don't > accidentally fall off a cliff... Yes, I know what const is for, and where and when appropriate.
The problem, as I said, that in practice, it just doesn't work. I'll elaborate: If working on any medium scale+ project where there are more than a few programmers and you use either a packaged framework and/or external C++ libraries, you quickly run into const problems.
You and your crew may do a great job of using const in the appropriate cases, but if you reference something else that doesn't, then you are at an impasse -- you must either use some disgusting cast to cast away const or modify your own code to remove const, even though your code is correct.
_This_ is what I mean when I say in practice, it doesn't work. Like Hendrik, I've used const for more than 10 years, and in my own code projects or other similar small projects, const is just fine. However, in just about every other large scale case, const in my/our code has led to problems, issues, and eventual removal because one or more of our third party libraries chose to implement a particular method that should have been const but wasn't.
My casual thoughts (i.e. I haven't thought through it in any detail) is that class methods should be _const_by_default_ and specifically de-const'd where/when appropriate.
Doug Harrison [MVP] - 30 Nov 2004 17:27 GMT >My casual thoughts (i.e. I haven't thought through it in any detail) is that >class methods should be _const_by_default_ and specifically de-const'd >where/when appropriate. That would take some getting used to, but it's consistent with the current fad(?) of explicitly granting privileges.
I think I'd genuinely like it applied to function parameters, most of which should be declared const, and most of which rarely are. I'm speaking of course about top-level const, e.g.
// What user should see: void f(int x); void g(char* x);
// What implementations normally would benefit from: void f(int const x) {...} void g(char* const x) {...}
You can do this already, of course, but it's a pain, and most people skip it, even though they may diligently declare local variables const.
While we're at it, let's disable copying of classes by default.
And fix the casual approach to overriding virtual functions, which is prone to accident.
Anything else? :)
 Signature Doug Harrison Microsoft MVP - Visual C++
Bret Pehrson - 30 Nov 2004 18:16 GMT > >My casual thoughts (i.e. I haven't thought through it in any detail) is that > >class methods should be _const_by_default_ and specifically de-const'd [quoted text clipped - 24 lines] > > Anything else? :) Except for the const stuff, looks a lot like C#...
Hendrik Schober - 01 Dec 2004 13:45 GMT > [...] > [quoted text clipped - 7 lines] > > Anything else? :) Make one-arg ctors explicit by default.
Schobi
 Signature SpamTrap@gmx.de is never read I'm Schobi at suespammers dot org
"The presence of those seeking the truth is infinitely to be prefered to those thinking they've found it." Terry Pratchett
Hendrik Schober - 01 Dec 2004 13:57 GMT > [...] > > [quoted text clipped - 9 lines] > > Make one-arg ctors explicit by default. Oh, and automagically insert 'break' statements before each 'case'. (Or however it's done -- I don't care. It's just that even after a dozen years of C/C++ I still forget this damn 'break' once in a while. OTOH, I rarely ever want to fall through to the next label.)
Schobi
 Signature SpamTrap@gmx.de is never read I'm Schobi at suespammers dot org
"The presence of those seeking the truth is infinitely to be prefered to those thinking they've found it." Terry Pratchett
Peteroid - 03 Dec 2004 01:41 GMT >>Oh, and automagically insert 'break' >>statements before each 'case'. (Or >>however it's done -- I don't care. .>>It's just that even after a dozen
>>years of C/C++ I still forget this >>damn 'break' once in a while. OTOH, >>I rarely ever want to fall through .>>to the next label.)
I agree! I often fall into that (rookie?) trap when using 'switch'. Maybe there should be two compiler directives to make either 'with break' or 'without break' the default in 'case' blocks ('without break' is the way it is hard-wired now), and the addition of an 'unbreak' ('continue'?) to override the default of 'break'.
Or, two 'switch's: 'switch' is as it is now (for compatibility), while 'switch_with_break' is a new one.
[==Peteroid==]
> > [...] > > > [quoted text clipped - 20 lines] > > Schobi Hendrik Schober - 01 Dec 2004 13:53 GMT > [...] > [quoted text clipped - 9 lines] > you must either use some disgusting cast to cast away const or modify your own > code to remove const, even though your code is correct. If there are ugly corners that you can not fix, isolate them using casts or by passing temporaries as arguments etc.
> _This_ is what I mean when I say in practice, it doesn't work. Like Hendrik, > I've used const for more than 10 years, and in my own code projects or other > similar small projects, const is just fine. However, in just about every other > large scale case, const in my/our code has led to problems, issues, and > eventual removal because one or more of our third party libraries chose to > implement a particular method that should have been const but wasn't. I don't think I ever have /removed/ a 'const' that should be there due to some other code getting it wrong. However, I have spent whole days on some projects just because I wanted to /add/ 'const' to some function that should have had it already but failed and that resulted in many other cases where a 'const' was missing. IIRC, there wasn't a single case where this did not discover a bug in the code base. Those that shook their heads when I "wasted" hours on this often soon were busy fixing the bugs found this way.
> My casual thoughts (i.e. I haven't thought through it in any detail) is that > class methods should be _const_by_default_ and specifically de-const'd > where/when appropriate. Not bad an idea. But I think there are a few more important cases where the default behaviour should be changed to the opposit.
Schobi
 Signature SpamTrap@gmx.de is never read I'm Schobi at suespammers dot org
"The presence of those seeking the truth is infinitely to be prefered to those thinking they've found it." Terry Pratchett
Hendrik Schober - 30 Nov 2004 08:29 GMT > [...] > > const is an abortion in C++. > > In theory, it sounds like a good idea. In practice, it just doesn't work. I have used to for ten years and it has proven to be very useful to me.
Schobi
 Signature SpamTrap@gmx.de is never read I'm Schobi at suespammers dot org
"The presence of those seeking the truth is infinitely to be prefered to those thinking they've found it." Terry Pratchett
Doug Harrison [MVP] - 29 Nov 2004 16:13 GMT >So, if I get you right, using operator[] on a std::map isn't const because >of the POSSIBILITY it might give be given a key not already in the map. >Thus, even if my code insures I won't ever ask for an entry for which a key >doesn't already exist, it can't be declared const since I might not write >good code in this regard. I wouldn't necessarily characterize this as a "good code" issue. To provide the non-const operator[], std::map has to be able to deal with:
m[k] = t;
for some k not already in the map. It would be subtle for the non-const operator[] to add items but for const operator[] to throw for items that don't already exist in the map.
>I believe I now understand, but feel it should have been the case that >operator[] was designed to allow const and to just cause an error if a >request for an entry where no key existed was asked for, and force people to >check on existence using the count() method (which returns 0 if the entry >doesn't exist and 1 if it does). That is, treat it much like trying to >access an array element that is out of bounds... I guess they figured that operator[] shouldn't change in definedness depending on const vs. non-const, though the standard library isn't entirely consistent with that philosophy. In any case, you can write your own indexer functions that throw for items not already in the map, at some loss of notational convenience. (Think vector::at, but as a non-member "lookup(m, k)" or something...)
(Speaking of gotchas, note also that an insert() that finds the key doesn't update the item already in the map. That got me once...)
>Thanks Doug! No problem.
 Signature Doug Harrison Microsoft MVP - Visual C++
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|