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 k
się try_emplace
i jest poza tym identyczne)
Jeśli element istnieje pod kluczem k
na mapie, to try_emplace
zwraca iterator do tego elementu i false
. W przeciwnym razie try_emplace
wstawia nowy element pod klucz k
i 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_type
skonstruowany za pomocąpiecewise_construct, forward_as_tuple(k), forward_as_tuple(std::forward<Args>(args)...)
(przeciążenie przyjmujące wartość odniesienia po prostu przenosi k
się forward_as_tuple
i znowu jest identyczne)
Ponieważ value_type
jest 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ż args
jest 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 T
przy użyciu ()
jako inicjator sprowadzający się do inicjalizacji wartości [dcl.init] /17.4 . Inicjalizacja wartości int
to inicjalizacja zerowa [dcl.init] / 8 . I zerowa inicjalizacja int
naturalnie inicjuje to int
do 0 [dcl.init] / 6 .
Więc tak, twój kod ma gwarancję zwrotu 0…