2008-11-04 14 views
85

El siguiente código dice que pasa el mapa como const en el método operator[] descarta calificadores:C++ descarta mapa de acceso calificadores (const)

#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; 
} 

¿Es esto debido a la posible asignación que se produce en el mapa de acceso? ¿No pueden declararse const las funciones con accesos de mapa?

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

+0

Sólo una pequeña crítica, pero mw puede declararse simplemente como MapWrapper mw; – luke

+0

Buen punto: escribo en un par de idiomas, así que tiendo a normalizar la sintaxis en ellos para que encajen en mi cabeza. :) – cdleary

+0

Puedo apreciar eso. Sin embargo, ten cuidado, en casos como este tienes una construcción y asignación de objetos extra que no son necesarios. – luke

Respuesta

118

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

T & operador [] (const clave Key &)

devuelve una referencia al valor que se asigna a una clave equivalente a la clave, la realización de la inserción si dicha clave no hace ya existe.

Como resultado, su función no pueden declararse const, y utilizar el mapa de operator[].

std::map's find() función le permite buscar una tecla sin modificar el mapa.

find() devuelve un iterator, o const_iterator a un std::pair que contiene tanto la clave (.first) y el valor (.second).

En C++ 11, también puede usar at() para std::map. Si el elemento no existe, la función arroja una excepción std::out_of_range, en contraste con operator [].

+6

adicionalmente: VALOR = map.find (KEY) -> second; Tuve que aprender que 'find()' devuelve un iterador, que es de tipo par. – FlipMcF

+4

Añadiría que ahora en C11 puede usar: std :: map :: at (key) y evitar el iterador. –

+2

Interesante. Pensaría que C++ distinguiría entre lvalue 'operator []' (por ejemplo 'foo [bar] = baz') y rvalue' operator [] '(por ejemplo' x = foo [bar] ') - lo último podría ser const. – Claudiu

10

No se puede usar el operador [] en un mapa que es const como el método no está const, ya que le permite modificar el mapa (se puede asignar a _MAP [clave]). Intenta usar el método find en su lugar.

+1

A modo de explicación: ¿qué debería hacer el operador del mapa [] si la clave no existe? Si el mapa no es const, la clave se agrega con valor construido por defecto. Si el mapa está const, ¿qué puede devolver el operador []? No hay ningún valor en esa clave. – Arkadiy

7

Algunas versiones más nuevas de los encabezados de GCC (4.1 y 4.2 en mi máquina) tienen funciones miembro no estándar map :: at() que se declaran const y throw std :: out_of_range si la clave no está en el mapa.

const mapped_type& at(const key_type& __k) const 

De una referencia en el comentario de la función, parece que esto ha sido sugerido como un nuevo miembro de la función de la biblioteca estándar.

+0

Supongo que es un pequeño capricho. La función at es parte del próximo estándar, pero no encuentro at() en el actual. –

+0

Archivado un informe de error: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46544 –

+0

'at' es parte de C++ 11. –

0

En primer lugar, no debe utilizar símbolos que comiencen con _ porque están reservados para la implementación del lenguaje/compilador. Sería muy fácil para _map ser un error de sintaxis en el compilador de alguien, y no tendría a nadie a quien culpar sino a usted mismo.

Si desea utilizar un guión bajo, colóquelo al final, no al comienzo. Probablemente cometió este error porque vio algún código de Microsoft haciéndolo. Recuerde, ellos escriben su propio compilador, por lo que pueden salirse con la suya. Aun así, es una mala idea.

el operador [] no solo devuelve una referencia, realmente crea la entrada en el mapa. Entonces no solo estás obteniendo un mapeo, si no hay ninguno, estás creando uno. Eso no es lo que pretendías.

+4

Su punto sobre '_' es simplemente incorrecto. Los identificadores que comienzan con dos guiones bajos ('__example') o identificadores que comienzan con un guión bajo y una letra mayúscula (' _Example') están reservados. '_example' no está reservado. – Ethan

9

Dado que operator[] no tiene una sobrecarga calificada, no se puede usar con seguridad en una función const-qualified.Probablemente esto se deba a que la sobrecarga actual se creó con el objetivo tanto de devolver como establecer valores clave.

su lugar, puede utilizar:

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

o, en C++ 11, se puede utilizar el operador de at():

VALUE = map.at(KEY); 
Cuestiones relacionadas