为什么 STL 映射的[]操作符不是常量?

举个人为的例子,为了回答这个问题:

void MyClass::MyFunction( int x ) const
{
std::cout << m_map[x] << std::endl
}

由于[]操作符是非 const 的,因此无法编译。

这很不幸,因为[]语法看起来非常干净:

void MyClass::MyFunction( int x ) const
{
MyMap iter = m_map.find(x);
std::cout << iter->second << std::endl
}

这一直困扰着我,为什么[]操作符是非常数的?

21163 次浏览

An index operator should only be const for a read-only container (which doesn't really exist in STL per se).

Index operators aren't only used to look at values.

Note for new readers.
The original question was about STL containers (not specifically about the std::map)

It should be noted there is a const version of operator [] on most containers.
It is just that std::map and std::set do not have a const version and this is a result of the underlying structure that implements them.

From std::vector

reference       operator[](size_type n)
const_reference operator[](size_type n) const

Also for your second example you should check for a failure to find the element.

void MyClass::MyFunction( int x ) const
{
MyMap iter = m_map.find(x);
if (iter != m_map.end())
{
std::cout << iter->second << std::endl
}
}

For std::map and std::unordered_map, operator[] will insert the index value into the container if it didn't previously exist. It's a little unintuitive, but that's the way it is.

Since it must be allowed to fail and insert a default value, the operator can't be used on a const instance of the container.

http://en.cppreference.com/w/cpp/container/map/operator_at

If you declare your std::map member variable to be mutable

mutable std::map<...> m_map;

you can use the non-const member functions of std::map within your const member functions.

Since operator[] might insert a new element into the container, it can't possibly be a const member function. Note that the definition of operator[] is extremely simple: m[k] is equivalent to (*((m.insert(value_type(k, data_type()))).first)).second. Strictly speaking, this member function is unnecessary: it exists only for convenience

Now that with C++11 you can have a cleaner version by using at()

void MyClass::MyFunction( int x ) const
{
std::cout << m_map.at(x) << std::endl;
}