web-dev-qa-db-ja.com

std :: unordered_map operator []は、存在しないキーに対してゼロ初期化を行いますか?

Cppreference.comによると、 std::map::operator[] 存在しない値の場合、ゼロ初期化を行います。

ただし、同じサイトでは std::unordered_map::operator[] ですが、これに依存する例があります。

もちろん、これは単なる参考サイトであり、標準ではありません。それで、以下のコードは大丈夫ですか?

#include <unordered_map>
int main() {
    std::unordered_map<int, int> map;
    return map[42];     // is this guaranteed to return 0?
}
25
hyde

話しているオーバーロードに応じて、_std::unordered_map::operator[]_は [[unord.map.elem] と同等です。

_T& operator[](const key_type& k)
{
    return try_­emplace(k).first->second;
}
_

(右辺値参照を受け取るオーバーロードは、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

それ以外の場合は、piecewise_­construct, forward_­as_­Tuple(k), forward_­as_­Tuple(std​::​forward<Args>(args)...)で作成された_value_­type_型のオブジェクトを挿入します

(右辺値参照をとるオーバーロードは、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)...));
_

_operator[]_から来るときはargsが空なので、これはつまり、引数なしでpairのメンバーとして構築されている新しい値 [pairs.pair]/14 直接初期化 [[class.base.init]/7 _()_を初期化子として使用してT型の値を初期化して値を初期化する [dcl.init] /17.4intの値の初期化はゼロ初期化 [dcl.init]/8 です。そして、intのゼロ初期化は、そのintを自然に0に初期化します [dcl.init]/6

つまり、コードは0を返すことが保証されています…

13
Michael Kenzel

あなたがリンクしたサイトではそれは言う:

デフォルトのアロケータが使用される場合、これにより、キーはキーからコピー構築され、マップされた値は値で初期化されます。

したがって、intvalue-initialized です。

値の初期化の影響は次のとおりです。

[...]

4)それ以外の場合、オブジェクトはゼロで初期化されます

これが結果が0である理由です。

21
Blaze