Dependendo de qual sobrecarga estamos falando, std::unordered_map::operator[]
é equivalente a [unord.map.elem]
T& operator[](const key_type& k)
{
return try_emplace(k).first->second;
}
(a sobrecarga tendo uma referência rvalue apenas se move k
para try_emplace
e é de outro modo idêntica)
Se um elemento existir sob a chave k
no mapa, try_emplace
retornará um iterador para esse elemento e false
. Caso contrário, try_emplace
insere um novo elemento sob a chave k
e retorna um iterador para isso e true
[unord.map.modifiers] :
template <class... Args>
pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
Interessante para nós é o caso de ainda não haver nenhum elemento [unord.map.modifiers] / 6 :
Caso contrário, insere um objeto do tipo value_type
construído compiecewise_construct, forward_as_tuple(k), forward_as_tuple(std::forward<Args>(args)...)
(a sobrecarga que toma uma referência rvalue apenas se move k
para forward_as_tuple
e, novamente, é idêntica)
Como value_type
é um pair<const Key, T>
[unord.map.overview] / 2 , isso nos diz que o novo elemento do mapa será construído como:
pair<const Key, T>(piecewise_construct, forward_as_tuple(k), forward_as_tuple(std::forward<Args>(args)...));
Como args
está vazio quando vem de operator[]
, isso se resume ao nosso novo valor sendo construído como membro dos pair
argumentos from from [pairs.pair] / 14, que é a inicialização direta [class.base.init] / 7 de um valor do tipo T
using ()
como inicializador, que se resume à inicialização de valor [dcl.init] /17.4 . A inicialização do valor de um int
é inicialização zero [dcl.init] / 8 . E a inicialização zero de um int
naturalmente inicializa isso int
para 0 [dcl.init] / 6 .
Então, sim, seu código está garantido para retornar 0…