mapas mapa impresion hacer editar diseñador cuadricula crear añadir c++ c++11 stdmap

c++ - mapa - layout qgis



Cuando debería usar std:: map:: at para recuperar el elemento del mapa (8)

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

Entonces, ¿cuándo deberías usar cuál?

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

at() tira si no hay ningún elemento para esa tecla. Como no debe usar excepciones para el flujo normal del programa, usar at() es decir "estoy seguro de que hay tal elemento". Pero con el beneficio adicional de que obtiene una excepción (y no un comportamiento indefinido) si está equivocado. No use esto si no está seguro de que el elemento exista.

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

He leído diferentes artículos en la 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 del mapa.

De acuerdo con la definition , std::map::at

Devuelve una referencia al valor mapeado del elemento identificado con la tecla k.

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

Para mí solo caso cuando vale la pena usar std::map::at cuando esté 100% seguro de que ese elemento con una clave particular existe, de lo contrario debería considerar el manejo de excepciones.

  1. ¿Hay algún caso en el que se considere std::map::at como la forma más eficiente y elegante de hacerlo? ¿En qué casos recomendarás usar std::map::at ?
  2. ¿Tengo razón en que es mejor usar map::find() cuando existe la posibilidad de no tener elemento con esa clave? Y map::find() es un enfoque más rápido y más elegante?

if ( map.find("key") != map.end() ) { // found } else { // not found }

PD

map::operator[] veces puede ser peligroso, porque si un elemento no existe, entonces lo insertará.

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


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

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

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

  • si solo desea saber si un elemento está presente en el map (o no), utilice count() .
  • si desea acceder al elemento, y debe estar en el map , entonces use at() .
  • si desea acceder al elemento y no sabe si está en el map o no, utilice find() ; no olvide verificar que el iterador resultante no sea igual al resultado de end() .
  • finalmente, si desea acceder al elemento si existe o crearlo (y acceder a él) si no lo hace, utilice el operator[] ; si no desea llamar al constructor predeterminado del tipo para crearlo, entonces use insert o emplace apropiadamente

Creo que depende de tu 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. Puede preferir

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

en expresiones sobre los más elaborados

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

Siempre que use el resultado de std::map::at() en una expresión, espera que el elemento exista y considere que un elemento faltante es un error. Entonces, una excepción es una buena opción para manejar eso.


Esto depende de cuáles sean 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 dos opciones sobre cómo manejarlo. Podría hacerlo a través de una excepción o podría devolver algún tipo de centinela que significa que no se encontró nada. Si desea lanzar una excepción, utilice at() ya que se lanzará la excepción por usted. Si no desea lanzar una excepción, utilice find() para no tener que lidiar con el manejo de una excepción solo para devolver un objeto centinela.


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

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

  • at es bueno si esperas que algo esté en el mapa y lanzarías una excepción si no fuera así. También puede acceder a los mapas de const en un asunto más conciso que find (donde no puedes usar op[] )

  • op[] es bueno si desea insertar un elemento predeterminado, como para el programa de conteo de palabras que pone un int 0 para cada palabra encontrada por primera vez (con las words[word]++; idiomáticas words[word]++; ).


Supongo que la diferencia es semántica.

std::map::at() 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 busca end() , compara claves y arroja la excepción donde sea necesario.

find() 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 utiliza find() + check para end() , está haciendo casi lo mismo que at does. Yo diría que la diferencia semántica es:

  • use at() cuando necesite un elemento en una ubicación específica, y suponga que está allí. En este caso, la situación del elemento que falta en el lugar deseado es excepcional, por lo que at() arroja 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 otros propósitos además de simplemente obtener su valor.

map :: at () devuelve una referencia de valor l, y cuando regresa 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 sea extremadamente cauteloso, ya que debe ocuparse de la invalidación del iterador .

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

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

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

C ++ Spec:

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. Requiere: key_type será CopyInsertable y mapped_type será DefaultInseable en * this. Devuelve: una referencia al 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: una referencia al mapped_type correspondiente a x en * this. Lanzamientos: un objeto de excepción de tipo out_of_range si no existe dicho elemento. Complejidad: Logarítmica.


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

Además, puede usar at() para acceder a los mapas de const.

Entonces, para sus preguntas:

  1. Recomendaré usar at() lugar de [] al acceder a los mapas de const y cuando la ausencia de elementos es un error de lógica.
  2. Sí, es mejor usar map::find() cuando no está seguro de que el elemento esté aquí: en este caso no es un error lógico y, por lo tanto, lanzar y atrapar std::logic_error excepción no será una forma muy elegante de programación, incluso si no pensamos en el rendimiento.