¿Por qué el operador [] no es constante para mapas STL?


89

Ejemplo elaborado, por el bien de la pregunta:

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

Esto no se compilará, ya que el operador [] no es constante.

Esto es lamentable, ya que la sintaxis [] parece muy limpia. En cambio, tengo que hacer algo como esto:

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

Esto siempre me ha molestado. ¿Por qué el operador [] no es constante?


5
¿Qué debería operator[]rendir en caso de que el elemento dado no exista?
Frerich Raabe

4
@Frerich Raabe: Lo mismo que la función del miembro at: throw std :: out_of_range
Jean-Simon Brochu

Respuestas:


90

Para std::mapy std::unordered_map, operator[]insertará el valor del índice en el contenedor si no existía previamente. Es un poco intuitivo, pero es así.

Dado que se debe permitir que falle e inserte un valor predeterminado, el operador no se puede usar en una constinstancia del contenedor.

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


3
std::setno tiene operator[].
Avakar

2
Esa es la respuesta correcta, pero una versión constante podría hacer lo mismo que el miembro "at". Eso es lanzar un std :: out_of_range ...
Jean-Simon Brochu

Cuando se usa para leer un valor, no hay un valor predeterminado para proporcionar. std::vectortiene un operador de lectura []que es const. mapdebería hacer lo mismo.
wcochran

51

Ahora que con C ++ 11 puede tener una versión más limpia usando at ()

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

4
Si maptiene const y no const at()s, ¿por qué no lo mismo también para operator[]? con la versión const no insertando nada sino tirando? (O devolver un opcional, cuando std :: opcional lo convierte en el estándar)
einpoklum

@einpoklum El punto de corrección constante es principalmente la verificación estática en tiempo de compilación. Prefiero que el compilador se queje antes que lanzar una excepción porque no usé objetos const correctamente.
Millie Smith

@einpoklum Muy tarde, pero para otros lectores: tener dos sobrecargas haciendo cosas tan diferentes sería terrible. La única razón por la que atviene en dos sabores es porque hace a return *this;, y la única diferencia entre las sobrecargas es el carácter constde la referencia devuelta. Los efectos reales de ambos ats son exactamente los mismos (es decir, sin efecto).
HTNW

28

Nota para nuevos lectores.
La pregunta original era sobre contenedores STL (no específicamente sobre std :: map)

Cabe señalar que existe una versión constante de operator [] en la mayoría de los contenedores.
Es solo que std :: map y std :: set no tienen una versión constante y esto es el resultado de la estructura subyacente que los implementa.

Desde std :: vector

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

Además, para su segundo ejemplo, debe verificar si no se encuentra el elemento.

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

1
std::setno tiene operator[]nada.
Todos

2

Dado que el operador [] podría insertar un nuevo elemento en el contenedor, no es posible que sea una función miembro constante. Tenga en cuenta que la definición de operador [] es extremadamente simple: m [k] es equivalente a (* ((m.insert (value_type (k, data_type ()))). First)). Second. Estrictamente hablando, esta función de miembro es innecesaria: existe solo por conveniencia


0

Un operador de índice solo debe ser constante para un contenedor de solo lectura (que realmente no existe en STL per se).

Los operadores de índice no solo se utilizan para observar valores.


6
La pregunta es, ¿por qué no tiene dos versiones sobrecargadas, una consty otra no const, como por ejemplo std::vector.
Pavel Minaev

-2

Si declara que su variable miembro std :: map es mutable

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

puede usar las funciones miembro no constante de std :: map dentro de sus funciones miembro constante.


15
Sin embargo, esta es una idea terrible.
GManNickG

7
La API para tu clase miente si haces eso. La función afirma que es constante, lo que significa que no modificará ninguna variable miembro, pero en realidad podría estar modificando el miembro de datos m_map.
Runcible

2
mutablese puede utilizar para miembros como std::mutex, cachés y ayudantes de depuración. Si el mapa se va a utilizar como caché para acelerar una constfunción "captadora" muy cara , entonces mutablees aceptable. Debe tener cuidado, pero no es una idea terrible por sí sola.
Mark Lakata
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.