2011-11-29 11 views
6

Estoy leyendo:¿Por qué solo los mapas no constantes proporcionan una recuperación asociativa de elementos directos similar a una matriz?

La biblioteca estándar de C++: un tutorial y de referencia de Nicolai M. Jossuttis

Es mi go-reservar cuando voy a utilizar algunos mecanismos en STL cualquier forma significativa. De todos modos, yo estaba releyendo rápidamente los capítulos sobre std :: mapa y algoritmos relacionados y me di cuenta de una frase que no había pensado antes:

mapas

no constante proporcionan un operador subíndice para el acceso directo elemento. Sin embargo, el índice del operador de subíndice no es la posición integral del elemento. ... etc.

¿Por qué solo se pueden usar mapas no constantes de la misma manera? Parece que sería bastante simple proporcionar semántica de solo lectura en este caso. Supongo que serían posibles excepciones si intentas recuperar un elemento con una clave que no existe (ya que no puedes agregar una nueva clave/valor al mapa si es constante).

Me gustaría entender el razonamiento detrás de esto si alguien puede arrojar algo de luz :) gracias!

+0

¿Cómo esperas que 'map [" foo "]' funcione en una instancia 'const' de' std :: map' si no hay un elemento coincidente? No puede crearlo ya que el 'map' es const y arrojar una expection diferiría del comportamiento no const que podría ser peligroso. – ereOn

Respuesta

11

¿Porque solo los mapas no constantes usarse en una matriz asociativa como forma?

Porque esos operadores devuelven una referencia al objeto que está asociado con una tecla en particular. Si el contenedor aún no contiene dicho objeto, operator[] inserta el objeto predeterminado. Ahora, si el contenedor es constante, no puede insertar ningún objeto en él, y no puede devolver una referencia a objetos no existentes, por eso estos operadores están disponibles solo para contenedores no constantes.

Lanzar una excepción en ese caso es posible, por supuesto, pero no es la mejor manera de abordar un caso bastante general cuando el objeto para una clave dada no existe. Básicamente, las excepciones son extremadamente costosas y son para situaciones excepcionales, y la anterior no lo es, por lo que no vale la pena.

La mejor manera sería devolver un iterador, pero el usuario tendría que comprobar si no es "final", lo que hará que el caso de uso sea similar a llamar a find(), por lo que es inútil. También es posible la devolución de iteradores o punteros para contenedores de solo constantes, pero eso rompe la semántica un poco y es confuso.

1

El [] -operator muta el recipiente: Si no existe la clave, se creará:

return m[1];  // **creates** m[1] if it doesn't exist 

return *m.find(1) // UB if m[1] doesn't exist (dereferencing m.end()) 

Además, [] siempre devuelve una referencia no constante, por lo que se puede decir m[1] = 2;. Por otro lado, find() un iterador cuya constness es que del propio mapa:

map_t m; 
*m.find(1) = 2; // Only OK if m[1] exists 
// *const_cast<map_t const &>(m).find(1) = 2; // error 
1

[] operador modifica el mapa, si la clave no existe.

Si la clave no existe, el mapa crea una nueva entrada con la clave, y un valor predeterminado para el valor asociado, y devuelve su referencia.Para que esto suceda, operator[] tiene que ser una función no const, lo que significa que no puede operar en la instancia const de .

8

En C++ 11 puede usar at() para obtener ese comportamiento "obtener valor correlacionado, sino arrojar excepción". Sobrecargar operator[] para hacer dos cosas diferentes (es decir, insertar nuevo par o lanzar) dependiendo de si un mapa es constante sería demasiado confuso y propenso a errores.

Cuestiones relacionadas