Re: Is there a proposal to fix the operator[] (rvalue/lvalue issues)??
Greg Herlihy wrote:
For programs that currently retrieve values by indexing a non-const
std::map - being able to access a const std::map in the same way does
seem useful. After all, most programmers expect the non-const and const
versions of an object to behave consistently.
but they wouldn't act consistently. When indexing a non-const map it
will insert an element where it doesn't exist, and you say it would not
do that when the map is const.
Users would write code to retrieve the values from a map, thinking they
are not modifying the map. The code would work, after all, with a
const-map but because it so happens that the map is non-const, it would
behave differently and insert elements.
Users would get used to using operator[] for lookup. Particularly as
users will be using shared_ptr<T> as the second (value) type in the map
and will know that none of the genuine elements contain empty
shared-pointers so when they retrieve one they will use that to mean
"does not exist".
Of course, if it adds an element, it will err silently, at this point.
It won't tell you it inserted an element and will appear to work
properly. And will continue to work properly while you are looking up
with operator[] because the element will not appear to have been added.
Then you call another function that iterates through the map and
suddenly comes across this element, calls a method that dereferences
the empty pointer and blows up.
Hard bug to find.
And just in case you think this won't happen, there are many times that
someone forgetrs to make a method const, and furthermore, there will be
instances where the map is mutable because lazy-evaluation is used. So
if the map is mutable the non-const overload will be used even when the
function is const. I know this could happen now anyway, but it is less
likely because users don't normally use operator[] for lookup.
Yes, we are protecting against poor programming here, but I don't see
the harm in doing that. The purpose of interfaces is to make life
easier for the programmer. An at() method would therefore be ideal. It
could even come with an extra flag parameter that can indicate whether
to throw or not on not-found. I think the default should be not to
throw (even though the normal behaviour of at() is to throw on
bounds-errors, but this is not a bounds-error because maps are
unbounded). My own functions that perform this kind of thing (actually
checked_inserter) not only has the option to throw, but you may supply
a method to print the key which by default is streaming but if the key
is not streamable you may pass in an alternative. (Actually you pass in
an operation to convert the key to something that is streamable. By
default it is a no-op convert).
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]