Por que o operador não é const para mapas STL?

Exemplo inventado, para o bem da questão:

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

Isso não será compilado, já que o operador [] não é const.

Isso é lamentável, já que a syntax [] parece muito limpa. Em vez disso, tenho que fazer algo assim:

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

Isso sempre me incomodou. Por que o operador [] não é const?

Para std::map e std::unordered_map , operator[] irá inserir o valor do índice no contêiner se ele não existir anteriormente. É um pouco não intuitivo, mas é assim que é.

Como deve ser permitido falhar e inserir um valor padrão, o operador não pode ser usado em uma instância const do contêiner.

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

Agora que com o C ++ 11 você pode ter uma versão mais limpa usando at ()

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

Nota para novos leitores.
A pergunta original era sobre contêineres STL (não especificamente sobre o std :: map)

Deve-se notar que há uma versão const do operador [] na maioria dos contêineres.
É apenas que std :: map e std :: set não têm uma versão const e isso é um resultado da estrutura subjacente que os implementa.

De std :: vector

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

Também para o seu segundo exemplo, você deve verificar se não encontrou o elemento.

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

Como o operador [] pode inserir um novo elemento no contêiner, não é possível que ele seja uma function de membro const. Note que a definição de operator [] é extremamente simples: m [k] é equivalente a (* ((m.insert (value_type (k, data_type ()))). First)). Estritamente falando, essa function de membro é desnecessária: existe apenas por conveniência

Um operador de índice deve ser apenas const para um contêiner somente leitura (que realmente não existe no STL, por si só).

Os operadores de índice não são usados ​​apenas para observar valores.

Se você declarar sua variável de membro std :: map para ser mutável

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

você pode usar as funções de membro não const de std :: map dentro de suas funções de membro const.