130

I tried to use the operator[] access the element in a const map, but this method failed. I also tried to use at() to do the same thing. It worked this time. However, I could not find any reference about using at() to access element in a const map. Is at() a newly added function in map? Where can I find more info about this? Thank you very much!

An example could be the following:

#include <iostream>
#include <map>

using namespace std;

int main()
{
        map<int, char> A;
        A[1] = 'b';
        A[3] = 'c';

        const map<int, char> B = A;

        cout << B.at(3) << endl; // it works
        cout << B[3] << endl;  // it does not work

}

For using "B[3]", it returned the following errors during compiling:

t01.cpp:14: error: passing ‘const std::map<int, char, std::less, std::allocator<std::pair<const int, char> > >’ as ‘this’ argument of ‘_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = int, _Tp = char, _Compare = std::less, _Alloc = std::allocator<std::pair<const int, char> >]’ discards qualifiers

The compiler used is g++ 4.2.1

user438383
  • 5,716
  • 8
  • 28
  • 43
icephere
  • 1,415
  • 2
  • 9
  • 5

4 Answers4

158

at() is a new method for std::map in C++11.

Rather than insert a new default constructed element as operator[] does if an element with the given key does not exist, it throws a std::out_of_range exception. (This is similar to the behaviour of at() for deque and vector.)

Because of this behaviour it makes sense for there to be a const overload of at(), unlike operator[] which always has the potential to change the map.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • Is is possible to have "at" return a default value instead of throwing an exception? – user1202136 Aug 30 '12 at 14:41
  • I'm using `at()` with in VS2013 on a project set to use VS2010 toolkit. I thought that meant I wasn't using C++11... But yet it compiles... ?? – thomthom Dec 07 '13 at 22:27
  • 3
    I just need to comment that it doesn't make sense to omit the const operator[], which could also throw an exception for an unmapped element instead of changing the map. – Spencer Mar 01 '18 at 15:37
  • @Spencer It would be surprising if the const and non-const overloads of operator[] had different effects. Normally, we expect that if some non-const objects or references in a program are made const, the program will continue to behave in the same way, as long as it compiles. Allowing only the non-const overload to throw exceptions can result in bugs that are not caught until runtime. – Brian Bi Feb 25 '19 at 17:55
  • @Brian Did you mean to say "Allowing only the **const** overload to throw exceptions"? – Spencer Feb 25 '19 at 19:23
  • @Spencer yes, sorry, that's what I meant. – Brian Bi Feb 25 '19 at 19:48
  • @Brian Thanks for clearing that up. Of course, I disagree with the reasoning in your original comment...it's possible that you consider something a bug that I'd consider expected behavior, and vice versa. – Spencer Feb 25 '19 at 22:52
  • @Spencer The "bug" in this case would be that after changing some non-const references to const references, the compiler would not warn you that some previously non-throwing operations have become potentially throwing. So then your program could crash in production because of the unhandled exception. – Brian Bi Feb 26 '19 at 00:07
  • 1
    @Brian Trading a silent, possibly corrupting error for a noisy one. That's a good thing. – Spencer Feb 26 '19 at 16:39
  • @Spencer no - in the status quo, there is no const overload of `operator[]`, so you get a guaranteed compile time error. If a const overload of `operator[]` were introduced with behaviour similar to `at`, then the guaranteed compile time error would turn into a runtime exception – Brian Bi Feb 26 '19 at 17:48
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/189089/discussion-between-spencer-and-brian). – Spencer Feb 26 '19 at 20:18
39

If an element doesn’t exist in a map, the operator [] will add it – which obviously cannot work in a const map so C++ does not define a const version of the operator. This is a nice example of the compiler’s type checker preventing a potential runtime error.

In your case, you need to use find instead which will only return an (iterator to the) element if it exists, it will never modify the map. If an item doesn’t exist, it returns an iterator to the map’s end().

at doesn’t exist and shouldn’t even compile. Perhaps this is a “compiler extension” (= a bug new in C++0x).

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
5

The []-operator will create a new entry in the map if the given key does not exists. It may thus change the map.

See this link.

vidstige
  • 12,492
  • 9
  • 66
  • 110
3

This comes as quite a surprise to me, but the STL map doesn't have a const index operator. That is, B[3] cannot be read-only. From the manual:

Since operator[] might insert a new element into the map, it can't possibly be a const member function.

I have no idea about at().

Beta
  • 96,650
  • 16
  • 149
  • 150