Cuándo debo usar std:: map:: at para recuperar el elemento del mapa


He leído diferentes artículos sobre web y preguntas en stackoverflow, pero para mí no está claro si hay algún caso exclusivo en el que sea mejor usar std::map::at para recuperar el elemento map.

Según la definición de , std::map::at

Devuelve una referencia al valor asignado del elemento identificado con clave k.

Si k no coincide con la clave de ningún elemento en el contenedor, el la función arroja un out_of_range salvedad.

Para mí solo caso cuando vale la pena utilizar std::map::at cuando usted 100% seguro de que el elemento con clave particular existe, de lo contrario debe considerar el manejo de excepciones.

  1. ¿Hay algún caso en el que std::map::at se considere la forma más eficiente y elegante de hacerlo? ¿En qué casos recomendará usar std::map::at ?
  2. ¿Tengo razón en que es mejor usar map::find() cuando existe la posibilidad de no tener elemento con tal clave? Y map::find(), es más rápido y más elegante ¿acercarnos?
if ( map.find("key") != map.end() )
{
    // found 

} else
{
    // not found
}

P. s

map::operator[] a veces puede ser peligroso, porque si un elemento no existe, entonces se inserta.

EDITADO: enlaces de alguna manera relacionados enlace 1 enlace 2 enlace 3 enlace 4 enlace 5 link 6

Author: Community, 2015-10-20

8 answers

Contrariamente a la mayoría de las respuestas existentes aquí, tenga en cuenta que en realidad hay4 métodos relacionados con la búsqueda de un elemento en un mapa (ignorando lower_bound, upper_bound y equal_range, que son menos precisos):

  • operator[] solo existe en la versión no-const, como se ha señalado, creará el elemento si no existe
  • at(), introducido en C++11, devuelve una referencia al elemento si existe y lanza una excepción de lo contrario
  • find() devuelve un iterador al elemento si existe o un iterador a map::end() si no lo hace
  • count() devuelve el número de tales elementos, en un map, esto es 0 o 1

Ahora que la semántica es clara, revisemos cuándo usar cuál:

  • si solo desea saber si un elemento está presente en el map (o no), entonces use count().
  • si desea acceder al elemento, y debe estar en el map, entonces use at().
  • si desea acceder al elemento, y no sabe si es en el map o no, entonces use find(); no olvide comprobar que el iterador resultante no es igual al resultado de end().
  • finalmente, si desea acceder al elemento si existe o crearlo (y acceder a él) si no lo hace, use operator[]; si no desea llamar al constructor de tipo predeterminado para crearlo, use insert o emplace apropiadamente
 44
Author: Matthieu M.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-06 20:09:32

std::map::at() lanza una excepción out_of_range si el elemento no se pudo encontrar. Esta excepción es una especie de logic_error excepción que para mí es una especie de sinónimo de assert() desde el punto de vista del uso: debería usarse para reportar errores en la lógica interna del programa, como la violación de precondiciones lógicas o invariantes de clase.

También puede usar at() para acceder a los mapas const.

Así que, para sus preguntas:

  1. Recomendaré usar at() en lugar de [] al acceder const mapea y cuando la ausencia de elementos es un error lógico.
  2. Sí, es mejor usar map::find() cuando no estás seguro de que el elemento esté aquí: en este caso no es un error lógico y por lo tanto lanzar y atrapar la excepción std::logic_error no será una forma muy elegante de programación, incluso si no pensamos en el rendimiento.
 21
Author: alexeykuzmin0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-20 12:31:11

Como ha señalado, hay tres formas diferentes de acceder a los elementos en un mapa: at(), operator[] y find() (también hay upper_bound, lower_bound y equal_range, pero esos son para circunstancias más complicadas donde es posible que desee encontrar un elemento siguiente / anterior, etc.)

Entonces, ¿cuándo debes usar cuál?

operator[] es básicamente "si no existe, cree uno con un elemento mapeado construido por defecto". Eso significa que no lanzará (excepto en los casos de esquina cuando la asignación de memoria lanza o uno de los constructores de clave o valor arrojados), y definitivamente obtienes una referencia al elemento que buscaste, ya sea el existente o el recién creado.

at() lanza si no hay ningún elemento para esa clave. Dado que no debe usar excepciones para el flujo normal del programa, usar at() es decir "Estoy seguro de que existe tal elemento."Pero con el beneficio adicional de que obtienes una excepción (y no un comportamiento indefinido) si estás equivocado. No use esto si no está seguro de que el el elemento existe.

find() dice " puede o no puede ser tal elemento, vamos a ver..."y le ofrece la posibilidad de reaccionar a ambos casos de manera diferente. Por lo tanto, es el enfoque más general.

 11
Author: Arne Mertz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-20 12:18:50

Los 3 de find, operator[] y at son útiles.

  • find es bueno si no desea insertar elementos accidentalmente, sino simplemente actuar si existen.

  • at es bueno si esperas que algo debería estar en un mapa y lanzarías una excepción si no lo fuera de todos modos. También puede acceder a const mapas en una materia más concisa que find (donde no se puede utilizar op[])

  • op[] es bueno si quiere insertar un elemento por defecto, tal en cuanto al programa de conteo de palabras que pone un int 0 por cada palabra encontrada por primera vez (con el modismo words[word]++;).

 5
Author: Bartek Banachewicz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-20 12:14:03

Esto depende de cuáles son los requisitos para esta función y cómo está estructurando el proyecto. Si se supone que debe devolver un objeto y no puede porque no se encontró, entonces le deja con dos opciones sobre cómo manejar eso. Podrías a través de una excepción o podrías devolver algún tipo de centinela que significa que no se encontró nada. Si desea lanzar una excepción, use at() ya que la excepción se lanzará para usted. Si no desea lanzar una excepción, utilice find() por lo tanto, no tiene que lidiar con el manejo de una excepción solo para devolver un objeto centinela.

 3
Author: NathanOliver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-20 12:09:48

Creo que depende de su caso de uso. El tipo de retorno de std::map::at() es una referencia lvalue al valor del elemento encontrado, mientras que std::map::find() devuelve un iterador. Tal vez prefieras

return myMap.at("asdf"s) + 42;

En expresiones sobre las más elaboradas

return myMap.find("asdf"s)->second + 42;

Cada vez que se usa el resultado de std::map::at() en una expresión, se espera que el elemento exista, y se considera un elemento faltante como un error. Así que una excepción es una buena opción para manejar eso.

 3
Author: cdonat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-20 12:14:30

Supongo que la diferencia es la semántica.

std::map::at() se ve así en mi máquina:

mapped_type&
at(const key_type& __k)
{
    iterator __i = lower_bound(__k);
    if (__i == end() || key_comp()(__k, (*__i).first))
        __throw_out_of_range(__N("map::at"));
    return (*__i).second;
}

Como puede ver, usa lower_bound, luego comprueba end(), compara claves y lanza la excepción donde sea necesario.

find() se ve así:

iterator
find(const key_type& __x)
{ return _M_t.find(__x); }

Donde _M_t es un árbol rojo-negro que almacena los datos reales. Obviamente, ambas funciones tienen la misma complejidad (logarítmica). Cuando usas find() + check for end(), estás haciendo casi lo mismo que at. Me diría que la diferencia semántica es:

  • use at() cuando necesite un elemento en una ubicación específica, y asuma que está allí. En este caso, la situación del elemento que falta del lugar deseado es excepcional, por lo tanto at() lanza una excepción.
  • use find() cuando necesite encontrar el elemento en el mapa. En este caso, la situación en la que el elemento no está presente es normal. También tenga en cuenta que find() devuelve un iterador que puede usar para fines distintos a simplemente obteniendo su valor.
 2
Author: SingerOfTheFall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-20 12:12:28

Map::at() devuelve una referencia de valor l, y cuando devuelve por referencia, puede usar todos sus beneficios disponibles, como el encadenamiento de métodos.

Ejemplo:

  map<int,typ> table;
  table[98]=a;
  table[99]=b;

  table.at(98)=table.at(99);

operator[] también devuelve el valor asignado por referencia, pero puede insertar un valor si no se encuentra la clave buscada, en cuyo caso el tamaño del contenedor aumenta en uno.

Esto requiere que seas extra cauteloso ya que tienes que cuidar de invalidación del iterador.

Tengo razón de que es mejor usar map:: find() cuando hay un posibilidad de no tener elemento con tal clave? Y mapa:: find () es ¿un enfoque más rápido y elegante?

Sí, semánticamente tiene sentido usar find() cuando no está seguro de la existencia de element.Hace que el código sea más fácil de entender incluso para un novato.

En cuanto a la eficiencia del tiempo, map generalmente se implementa como un árbol RB/algún árbol de búsqueda binaria balanceada y, por lo tanto, la complejidad es O(logN) para find().

Especificación de C++:

T& operator [] (const key_type& x);
Efectos: Si no hay una clave equivalente a x en el mapa, inserta value_type (x, T ()) en el mapa. Se requiere: key_type será CopyInsertable y mapped_type será DefaultInsertable en * this. Devuelve: Una referencia a la mapped_type correspondiente a x en * this. 4 Complejidad: logarítmica.

T & at (const key_type & x);
const T & at (const key_type& x) const; Devuelve: referencia a el mapped_type correspondiente a x en * this. Throws: Un objeto de excepción de tipo out_of_range si no hay tal elemento presente. Complejidad: logarítmica.

 2
Author: basav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:46:58