A seconda del sovraccarico di cui stiamo parlando, std::unordered_map::operator[]
equivale a [unord.map.elem]
T& operator[](const key_type& k)
{
return try_emplace(k).first->second;
}
(il sovraccarico che prende un riferimento di valore si sposta appena k
in try_emplace
ed è altrimenti identico)
Se un elemento esiste sotto chiave k
nella mappa, quindi try_emplace
restituisce un iteratore a quell'elemento e false
. Altrimenti, try_emplace
inserisce un nuovo elemento sotto la chiave k
e restituisce un iteratore a quello e true
[unord.map.modifiers] :
template <class... Args>
pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
Interessante per noi è il caso in cui non ci siano ancora elementi [unord.map.modifiers] / 6 :
Altrimenti inserisce un oggetto di tipo value_type
costruito conpiecewise_construct, forward_as_tuple(k), forward_as_tuple(std::forward<Args>(args)...)
(il sovraccarico che prende un riferimento di valore si sposta k
in forward_as_tuple
e, di nuovo, è altrimenti identico)
Poiché value_type
è un pair<const Key, T>
[unord.map.overview] / 2 , questo ci dice che il nuovo elemento della mappa sarà costruito come:
pair<const Key, T>(piecewise_construct, forward_as_tuple(k), forward_as_tuple(std::forward<Args>(args)...));
Poiché args
è vuoto quando proviene da operator[]
, ciò si riduce al nostro nuovo valore che viene costruito come membro del pair
from no argomenti [pairs.pair] / 14 che è l'inizializzazione diretta [class.base.init] / 7 di un valore di tipo T
usando ()
come inizializzatore che si riduce all'inizializzazione del valore [dcl.init] /17.4 . L'inizializzazione del valore di an int
è zero inizializzazione [dcl.init] / 8 . E zero inizializzazione di un int
inizializza naturalmente int
a 0 [dcl.init] / 6 .
Quindi sì, il tuo codice è garantito per restituire 0 ...