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_emplaceed è altrimenti identico)
Se un elemento esiste sotto chiave knella mappa, quindi try_emplacerestituisce un iteratore a quell'elemento e false. Altrimenti, try_emplaceinserisce un nuovo elemento sotto la chiave ke 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_typecostruito conpiecewise_construct, forward_as_tuple(k), forward_as_tuple(std::forward<Args>(args)...)
(il sovraccarico che prende un riferimento di valore si sposta kin forward_as_tuplee, 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 pairfrom no argomenti [pairs.pair] / 14 che è l'inizializzazione diretta [class.base.init] / 7 di un valore di tipo Tusando ()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 intinizializza naturalmente inta 0 [dcl.init] / 6 .
Quindi sì, il tuo codice è garantito per restituire 0 ...