2010-12-29 6 views
13

Tengo un mapa como éste¿Es seguro obtener un objeto en std :: map por referencia?

map<int,object> objmap; 
object& obj = objmap.find(num)->second; 
object& obj2 = objmap[num]; 

Independientemente de los cambios que hacer en el objeto que se refleja en el mapa. Algo similar no se puede hacer en un vector ya que cambia la ubicación de los objetos cuando quiere más espacio. ¿Es seguro hacerlo en un std :: map? y es aconsejable? La segunda versión da un error ya que mi objeto no tiene un constructor vacío. Si declaro que un constructor vacío no hace nada, ¿funcionarán las dos líneas de la misma manera?

Respuesta

18

Mientras el objeto en cuestión no se elimine del mapa, entonces sí es seguro. Una vez insertados en un mapa, los objetos no se mueven aunque se agreguen o eliminen otros elementos.

object& obj = objmap.find(num)->second; 

Esto puede ser peligroso si no está seguro de que un elemento con clave num existe realmente en el mapa. Si no está seguro, puede usar la sobrecarga de insert que devuelve iterator y bool que indica si se insertó un nuevo elemento o si un elemento con la clave dada ya estaba presente en el mapa.

E.g.

object& obj = objmap.insert(std::make_pair(num, object(arg1, arg2, argN))).first->second; 
+1

¿Sabes dónde y cómo encontrar dicha información en los documentos? En realidad, ni siquiera sabía cómo buscar esta respuesta: ¿cuál es la forma correcta de decir "los objetos no se mueven"? Supongo que las especificaciones deben definir esto con precisión, ya que es una diferencia tan importante entre un vector y un mapa. – Flynsee

11

Esto es seguro siempre que el elemento no se elimine del mapa.

Sin embargo, la segunda línea no es muy segura:

object& obj = objmap.find(num)->second; 

Si no hay elementos con llave num en el mapa, find volverá objmap.end(). Esta posibilidad debe ser probado antes de dereferencing el iterador devuelto:

const std::map<int, object>::iterator it = objmap.find(num); 
if (it != objmap.end()) 
{ 
    object& obj = it->second; 
    /* ... */ 
} 

Ahora bien, si el objetivo no es realmente para encontrar pero realmente para insertar, llamando operator[] es una posibilidad (aunque, como ya se ha notado, se requiere el valor para proporcionar un constructor sin parámetros). Pero hay que entender que se trata de dos cosas muy diferentes:

  • findsólo se encuentra: si no se encuentra la clave, nada se inserta y la end iterador se devuelve
  • operator[] siempre vuelve una referencia a un valor en el mapa: si la clave está ausente, se produce una inserción (para un valor construido predeterminado: así el requisito del constructor)
1

Si desea realizar cambios en el objeto en el mapa que se reflejará, es probable que desee cambiar su mapa para almacenar punteros a los objetos en lugar de los objetos en sí. Las referencias pueden funcionar siempre que no haga nada con el objeto entre la referencia que lo invalidaría.

Por ejemplo, el código siguiente se rompería el uso de referencias:

object& obj = objmap.find(num)->second; 
objmap.erase(objmap.find(num)); // should check for objmap.end() - left out for simplicity 
obj.DoSomething(); // this object has been destroyed, so the reference is invalid 
4

Si su pregunta es si el std::map invalida sus iteradores en sus funciones mutando entonces la respuesta es negativa. Las garantías estándar std::map no invalidan sus iteradores.

0

Hacer lo que está haciendo es una forma común de implementar el almacenamiento en caché.

Si el artículo ya está allí, el operador [] devuelve el artículo. Si no está allí, creará un "espacio en blanco" con el constructor predeterminado y podrá escribir en él para usarlo más adelante.

Por supuesto, uno comúnmente usa shared_ptr como el value_type que tendrá un valor "vacío" cuando se cree. En este caso, necesita obtener el shared_ptr por referencia para que pueda llamar a reset() en él.

Al igual que con cualquier colección/almacenamiento en caché, etc., debe tener cuidado con los problemas de seguridad de subprocesos si se está realizando en una aplicación de subprocesos múltiples.

Lo que no estoy seguro de que quisiera saber es si podría guardar la referencia en algún lugar (o un puntero) y esperar que sea válida más adelante cuando se agreguen otros elementos al mapa, y sí, será .

Cuestiones relacionadas