2010-11-24 21 views
10

Tengo un mapa desordenado que almacena el int como clave un puntero como valor. Necesito verificar la existencia de la clave. Si la clave no está disponible, necesito insertar la clave y el valor. ¿Cuál es el mejor enfoque?Pregunta básica al asignar valor a unordered_map

Gracias.

unordered_map<int, classA*>testMap; 
classA* ptr = testMap[1]; 
if(ptr == NULL) 
    testMap[1] = new classA; 


OR 

unordered_map<int, classA*>::iterator it = testMap.find(1); 
if(it == testMap.end()) 
{ 
    testMap.insert(make_pair(1, new classA)); 
} 
+0

Le sugiero que almacene sus instancias 'classA' creadas dinámicamente en' std :: shared_ptr': 'std :: unordered_map >'. Puede crear las instancias usando 'std :: make_shared (... ctr params ...)'. Esto lo libera de las preocupaciones de las filtraciones de recursos. –

+0

El primer enfoque o la variante que evita la segunda búsqueda podría ser mejor si puede asegurarse de que nunca tenga punteros nulos válidos en el mapa. Sin embargo, como no has declarado esa condición previa, yo elegiría el segundo enfoque seguro. Puede usar la función count() en lugar de buscar y/o deshacerse de la variable local it para borrar el código. –

Respuesta

6

Ninguno de estos métodos es bueno porque ambos usan dos consultas en el mapa donde uno sería suficiente.

Un método mejor es la recuperación de una referencia al elemento, y si esa referencia es un puntero nulo, asigne a la misma:

classA*& ptr = testMap[1]; 
if (ptr == 0) 
    ptr = new classA; 

Esto funciona porque la consulta de un elemento no existe en un mapa inserta automáticamente (construido por defecto, por lo tanto, se insertará un puntero nulo) y operator[] devuelve una referencia a ese elemento (ya sea de nueva creación o ya existente).

Pero observe que la semántica entre este método (o su primer método) y su segundo método difiere sutilmente: su segundo método solo inserta el elemento si la clave no existe en el mapa. Mi método (y su primer método) también crean un nuevo elemento si la clave ya existía, pero su valor era un puntero nulo.

+4

¿Qué pasa si esa clave ya existe y 'NULL' es un valor válido para ella? – Nate

+0

Sin embargo, esta no es una buena idea en general. Si estaba almacenando algo que no sean punteros, es posible que no tenga un valor predeterminado adecuado para probar. Además, la eficiencia no es un problema aquí, ya que la asignación de memoria llevará mucho más tiempo que la búsqueda. –

+0

@Nate: ver edición. ;-) –

0

Yo haría lo siguiente:

typedef unordered_map<int, classA*>::iterator my_iterator; 
std::pair<my_iterator, my_iterator> range = testMap.equal_range(1); 
if (range.first == range.second) //element not in map 
{ 
    testMap.insert(range.first, new classA); 
} 

EDIT: Gracias a Lijie para señalar que esto no tiene sentido. equal_range devuelve y [end, end] par si el valor no se encuentra para underoded_map.

+0

Si el elemento no está en 'desordenados_mapas', ambos iteradores devueltos por' igual_cuerpo' son 'fin()'. Así que dudo que la sugerencia de 'insertar' sea útil. (es decir, es equivalente a 'testMap.insert (testMap.end(), new classA)', que en cualquier caso es un error, debe ser un par). – lijie

+0

Sí, tienes razón, estaba pensando en un mapa estándar ordenado, lo siento. No estoy seguro de lo que quiere decir con un error, underoder_map tiene una función de inserción que toma dos argumentos, un iterador y un valor: http://msdn.microsoft.com/en-us/library/bb982322.aspx –

1

El segundo es el mejor enfoque. En el primero, cuando hace classA* ptr = testMap[1], está creando un elemento en el hash con el valor predeterminado de NULL.

Si fueras a cambiar el valor del mapa a algo que no sea un puntero (tal vez un vector por ejemplo), es posible que no tengas un valor predeterminado adecuado para contrastar. Además, en el futuro, NULL podría ser un valor válido para su mapa, por lo que su prueba de valor predeterminado no tendría sentido.

+2

¿Por qué? el voto abajo? –

+0

No he votado negativamente, pero diría que el segundo enfoque tiene otra razón: nunca creará entradas que no sean válidas. –

0

En términos de eficiencia, creo que son equivalentes.

En el primer caso, si la entrada no existe entonces la llamada a:

classA* ptr = testMap[1]; 

realidad va a crear un elemento vacío en el mapa que usted entonces poblar durante la instrucción if.

El segundo solo agregará una entrada al mapa cuando llame al insert.

¡Así que supongo que todo se ajusta a tu estilo!

Cuestiones relacionadas