W zależności od przeciążenia, o którym mówimy, std::unordered_map::operator[]jest równoważne z [unord.map.elem]
T& operator[](const key_type& k)
{
return try_emplace(k).first->second;
}
(przeciążenie przyjmujące wartość odniesienia po prostu przenosi księ try_emplacei jest poza tym identyczne)
Jeśli element istnieje pod kluczem kna mapie, to try_emplacezwraca iterator do tego elementu i false. W przeciwnym razie try_emplacewstawia nowy element pod klucz ki zwraca iterator do tego i true [unord.map.modifiers] :
template <class... Args>
pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
Interesujący jest dla nas brak elementu [unord.map.modifiers] / 6 :
W przeciwnym razie wstawia obiekt typu value_typeskonstruowany za pomocąpiecewise_construct, forward_as_tuple(k), forward_as_tuple(std::forward<Args>(args)...)
(przeciążenie przyjmujące wartość odniesienia po prostu przenosi księ forward_as_tuplei znowu jest identyczne)
Ponieważ value_typejest to pair<const Key, T> [unord.map.overview] / 2 , oznacza to, że nowy element mapy zostanie skonstruowany jako:
pair<const Key, T>(piecewise_construct, forward_as_tuple(k), forward_as_tuple(std::forward<Args>(args)...));
Ponieważ argsjest pusty, gdy przychodzi z operator[], sprowadza się to do tego, że nasza nowa wartość jest konstruowana jako element składowy „pair no arguments [pairs.pair] / 14, który jest bezpośrednią inicjalizacją [class.base.init] / 7 wartości typu Tprzy użyciu ()jako inicjator sprowadzający się do inicjalizacji wartości [dcl.init] /17.4 . Inicjalizacja wartości intto inicjalizacja zerowa [dcl.init] / 8 . I zerowa inicjalizacja intnaturalnie inicjuje to intdo 0 [dcl.init] / 6 .
Więc tak, twój kod ma gwarancję zwrotu 0…