2009-02-03 16 views
43

Tengo un std::map así:¿Los mapas STL inicializan los tipos primitivos en la inserción?

map<wstring,int> Scores; 

Almacena nombres de los jugadores y las puntuaciones. Cuando alguien recibe una puntuación yo simplemente hago:

Scores[wstrPlayerName]++; 

cuando no hay ningún elemento en el mapa con la tecla wstrPlayerName se creará uno, pero lo hace inicializar a cero o nula antes del incremento o se trata deja sin definir ?

¿Debo verificar si el elemento existe cada vez antes del incremento?

Respuesta

61

operador [] se ve así:

Value& map<Key, Value>::operator[](const Key& key); 

Si llama con una llave que es aún no está en el mapa, se usará por defecto-construir una nueva instancia de Valor, lo puso en el mapa bajo clave que ingresó y le devuelve una referencia. En este caso, usted tiene:

map<wstring,int> Scores; 
Scores[wstrPlayerName]++; 

Valor aquí es int, y son enteros como 0-construida por defecto, como si los inicializado con int(). Otros tipos primitivos se inicializan de manera similar (por ejemplo , doble(), largo(), bool(), etc.).

Al final, su código pone un nuevo par (wstrPlayerName, 0) en el mapa, luego devuelve una referencia al int, que luego se incrementa. Por lo tanto, no es necesario probar si el elemento existe aún si desea que las cosas comiencen desde 0.

11

Esto construirá por defecto una nueva instancia de value. Para los enteros, la construcción predeterminada es 0, por lo que funciona de la manera prevista.

+1

Para enteros, * construcción * predeterminada no es realmente una cosa. La inicialización * predeterminada * los deja sin inicializar a menos que sean estáticos. Maps * value *: inicializa los elementos, por lo que en el caso de los enteros obtiene la inicialización cero. – juanchopanza

5

No debe probar si el elemento existe antes de incrementarlo. El operador [] hace exactamente lo que necesita que haga, como han dicho otros.

Pero, ¿qué ocurre si el valor predeterminado no funciona para usted? En su caso, la mejor forma de determinar si el elemento ya existe es intentar insertarlo. La función de miembro insert para std::map devuelve un std::pair<iterator, bool>. Si la inserción tiene éxito o falla, el primer elemento del par apuntará al objeto deseado (ya sea el nuevo o el que ya estaba presente). A continuación, puede modificar su valor como mejor le parezca.

4

Gracias por la ayuda.

Así las std :: mapas establezca los valores de tipo primitivo a 0.

Me preguntaba porque pensé de tipo primitivo cosas son siempre indefinido cuando se creó.

si escribo algo como:

int i; 
i++; 

El compilador me advierte que i es indefinido y cuando corro el programa por lo general no es cero.

+7

En realidad es una característica del lenguaje C++. Si llama explícitamente al constructor de int (int i = int()) como std :: map, se inicializará a cero. Un desnudo int aún no será inicializado. –

+2

de hecho, porque "int i;" no inicializará por defecto el int (a diferencia de los tipos de clases). dejará su valor indefinido. mismo: struct a {int i; }; << el valor de i no está definido. struct a {a(): i() {} int i; }; << el valor de I es 0 –

+0

Espera. Si tiene struct A {int i; }; y luego creas un objeto de tipo A, p. A myA = A(); entonces myA.i será 0 porque llamar/usar A() habrá inicializado el total de myA en 0, por lo tanto, seré 0. Ver http://en.cppreference.com/w/cpp/language/zero_initialization – Will

1

Verifique las reglas para la inicialización.

Ver la sección 4.9.5 Inicialización de C++ Prog Lang o C++ std book. Dependiendo de si su variable es local, estática, definida por el usuario o const la inicialización predeterminada puede suceder.

En este caso, int se llama POD (tipo de datos antiguo simple). Cualquier variable POD automática (creada en el montón/variable local) no se inicializa por defecto. Por lo tanto, para ti "i" arriba no tendrá valor cero.

Siempre haga la costumbre de inicializar POD cuando se define en el montón. Incluso puede usar int() para inicializar el valor.

+3

Lo que ha dicho sobre los POD es correcto, pero el OP pregunta por la inicialización realizada por std :: map. Su respuesta no se aplica y puede ser confusa para los lectores, ya que parece contradecir las otras respuestas. – MatthewD

+0

Muy bien, tu respuesta está respondiendo a la respuesta de @Calmarius, que ahora está ** debajo ** (no ** arriba **) mientras lo estoy leyendo ahora. Esto realmente debería ser un comentario allí, no una respuesta separada. – MatthewD

+0

Como respuesta a la pregunta publicada, esto es completamente incorrecto. – juanchopanza

Cuestiones relacionadas