Dependiendo de qué sobrecarga estamos hablando, std::unordered_map::operator[]
es equivalente a [unord.map.elem]
T& operator[](const key_type& k)
{
return try_emplace(k).first->second;
}
(la sobrecarga de tomar un valor p-referencia sólo se mueve k
en try_emplace
y es por lo demás idéntico)
Si existe un elemento bajo la clave k
en el mapa, entonces try_emplace
devuelve un iterador a ese elemento y false
. De lo contrario, try_emplace
inserta un nuevo elemento debajo de la clave k
y devuelve un iterador a eso y true
[unord.map.modifiers] :
template <class... Args>
pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
Interesante para nosotros es el caso de que todavía no haya ningún elemento [unord.map.modifiers] / 6 :
De lo contrario, inserta un objeto de tipo value_type
construido conpiecewise_construct, forward_as_tuple(k), forward_as_tuple(std::forward<Args>(args)...)
(la sobrecarga de tomar un valor p-referencia sólo se mueve k
en forward_as_tuple
y, de nuevo, es por lo demás idéntico)
Como value_type
es un pair<const Key, T>
[unord.map.overview] / 2 , esto nos dice que el nuevo elemento del mapa se construirá como:
pair<const Key, T>(piecewise_construct, forward_as_tuple(k), forward_as_tuple(std::forward<Args>(args)...));
Como args
está vacío cuando viene de operator[]
, esto se reduce a nuestro nuevo valor que se construye como miembro de los pair
argumentos sin par [pair.pair] / 14, que es la inicialización directa [class.base.init] / 7 de un valor de tipo T
usando ()
como inicializador que se reduce a inicialización de valor [dcl.init] /17.4 . La inicialización del valor de un int
es inicialización cero [dcl.init] / 8 . Y la inicialización cero de un int
naturalmente inicializa eso int
a 0 [dcl.init] / 6 .
Entonces sí, su código está garantizado para devolver 0 ...