В зависимости от того, о какой перегрузке мы говорим, std::unordered_map::operator[]это эквивалентно [unord.map.elem]
T& operator[](const key_type& k)
{
return try_emplace(k).first->second;
}
(перегрузка принимает RValue-ссылку просто перемещается kв try_emplaceи в остальном идентичны)
Если элемент существует под ключом kна карте, то try_emplaceвозвращает итератор для этого элемента и false. В противном случае try_emplaceвставляет новый элемент под ключом kи возвращает итератор для него и true [unord.map.modifiers] :
template <class... Args>
pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
Для нас интересен случай, когда еще не было элемента [unord.map.modifiers] / 6 :
В противном случае вставляет объект типа, созданного value_typeсpiecewise_construct, forward_as_tuple(k), forward_as_tuple(std::forward<Args>(args)...)
(перегрузка принимает RValue-ссылку просто перемещается kв forward_as_tupleи, опять же , в остальном идентичны)
Поскольку value_typeэто pair<const Key, T> [unord.map.overview] / 2 , это говорит нам о том, что новый элемент карты будет построен как:
pair<const Key, T>(piecewise_construct, forward_as_tuple(k), forward_as_tuple(std::forward<Args>(args)...));
Так argsкак при поступлении из него пусто operator[], это сводится к тому, что наше новое значение создается как член pairиз аргументов from no [pair.pair] / 14, что является прямой инициализацией [class.base.init] / 7 значения типа, Tиспользуя ()как инициализатор, который сводится к инициализации значения [dcl.init] /17.4 . Значением инициализации intявляется нулевая инициализация [dcl.init] / 8 . И нулевая инициализация intестественно инициализирует это intк 0 [dcl.init] / 6 .
Так что да, ваш код гарантированно вернет 0 ...