Topic: Why no const overload for map::operator[]?
Author: Bruce Visscher <bvisscher@spyder.net>
Date: 1996/10/21 Raw View
I had wondered this when using the HP implementation of the STL. I was
pleased to see it had been added to the January 1996 DWP. However, I
have since been informed that it has been dropped in recent revisions of
the DWP being deemed a "mistake". Why is this? To me it is needed for
orthogonality. The implementation could be:
namespace std {
//...
template<class Key, class T, class Compare=less<Key>, class
Allocator=allocator> {
//...
public:
const mapped_type operator[](const Key& key) const {
const_iterator i=find(key);
return (i==end()) ? T() : i->second;
}
//...
};
//...
}
Alternatively, it could return a const reference to a statically
allocated, defaultly constructed T:
const mapped_type& operator[](const Key& key) const {
const_iterator i=find(key);
if(i==end()) {
static const T* p(0);
if(!p) {
__implementation_defined_reentrancy_guard g;
if(!p) {
static const T t;
p=&t
}
}
return *p;
}
return i->second();
}
More complicated, but avoids unnecessary constructors and destructors
while retaining thread safety. (The double check of p is due to a
comp.lang.c++.moderated article by James Kanze.) As far as I'm
concerned either implementation could be allowed by the standard.
Reasons for proposing that this be added (back) to the class are that it
could potentially simplify a lot of code while encouraging rather than
discouraging const correctness. Why should functions that have const
access to a map necessarily be syntactically messier than functions with
mutable access?
The only reason against it that I can think of is that the difference in
semantics between the mutating overload and the const version would be
surprising. This "surprise" is however due (IMHO) to the somewhat
surprising behavior of the mutating version:
#include <iostream>
#include <map>
using std::map;
usung std::cout;
void f(map<int, int>& m) {
for(int i=0; i<100; ++i) cout << m[i];
}
void g(const map<int, int>& m) {
for(int i=0; i<100; ++i) cout << m[i];
}
If passed an empty map, f() would add 100 pairs of ints but g() would
not. To me, the behavior of g() is more intuitive than that f().
Admitedly this issue is not as important as some others (e.g., exception
safety) but I would like to know if anyone else feels this is needed.
Bruce
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: sean@delta.com (Sean L. Palmer)
Date: 1996/10/23 Raw View
> If passed an empty map, f() would add 100 pairs of ints but g() would
> not. To me, the behavior of g() is more intuitive than that f().
>
> Admitedly this issue is not as important as some others (e.g., exception
> safety) but I would like to know if anyone else feels this is needed.
Have to agree with you here. Many times you want just to check if
something is in the map, without adding one if it doesn't exist, and it
would be damn handy to be able to do it using [] syntax.
I've had to make default constructors for map-stored items that default
the stored value to some nonsense value such as -1 and check for that,
or using find().
Surely a better way can be found.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]