C++ map access discards qualifiers (const)

C++StlConstantsMaps

C++ Problem Overview


The following code says that passing the map as const into the operator[] method discards qualifiers:

#include <iostream>
#include <map>
#include <string>

using namespace std;

class MapWrapper {
public:
    const int &get_value(const int &key) const {
        return _map[key];
    }

private:
    map<int, int> _map;
};

int main() {
    MapWrapper mw;
    cout << mw.get_value(42) << endl;
    return 0;
}

Is this because of the possible allocation that occurs on the map access? Can no functions with map accesses be declared const?

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

C++ Solutions


Solution 1 - C++

std::map's operator [] is not declared as const, and cannot be due to its behavior:

> T& operator[] (const Key& key) > > Returns a reference to the value that is mapped to a key equivalent to key, performing insertion if such key does not already exist.

As a result, your function cannot be declared const, and use the map's operator[].

std::map's find() function allows you to look up a key without modifying the map.

find() returns an iterator, or const_iterator to an std::pair containing both the key (.first) and the value (.second).

In C++11, you could also use at() for std::map. If element doesn't exist the function throws a std::out_of_range exception, in contrast to operator [].

Solution 2 - C++

Since operator[] does not have a const-qualified overload, it cannot be safely used in a const-qualified function. This is probably because the current overload was built with the goal of both returning and setting key values.

Instead, you can use:

VALUE = map.find(KEY)->second;

or, in C++11, you can use the at() operator:

VALUE = map.at(KEY);

Solution 3 - C++

You cannot use operator[] on a map that is const as that method is not const as it allows you to modify the map (you can assign to _map[key]). Try using the find method instead.

Solution 4 - C++

Some newer versions of the GCC headers (4.1 and 4.2 on my machine) have non-standard member functions map::at() which are declared const and throw std::out_of_range if the key is not in the map.

const mapped_type& at(const key_type& __k) const

From a reference in the function's comment, it appears that this has been suggested as a new member function in the standard library.

Solution 5 - C++

First, you should not be using symbols beginning with _ because they are reserved to the language implementation/compiler writer. It would be very easy for _map to be a syntax error on someone's compiler, and you would have no one to blame but yourself.

If you want to use an underscore, put it at the end, not the beginning. You probably made this mistake because you saw some Microsoft code doing it. Remember, they write their own compiler, so they may be able to get away with it. Even so, it's a bad idea.

the operator [] not only returns a reference, it actually creates the entry in the map. So you aren't just getting a mapping, if there is none, you are creating one. That's not what you intended.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioncdlearyView Question on Stackoverflow
Solution 1 - C++lukeView Answer on Stackoverflow
Solution 2 - C++RichardView Answer on Stackoverflow
Solution 3 - C++nlativyView Answer on Stackoverflow
Solution 4 - C++Nathan KitchenView Answer on Stackoverflow
Solution 5 - C++DovView Answer on Stackoverflow