web-dev-qa-db-ja.com

std :: mapを反復処理する順序はわかっていますか(標準で保証されていますか)?

つまり、std::mapの要素はキーに従ってソートされていることがわかります。したがって、キーが整数であるとしましょう。 forを使用してstd::map::begin()からstd::map::end()に反復する場合、標準では、昇順でソートされたキーを持つ要素を反復処理することが保証されますか?


例:

std::map<int, int> map_;
map_[1] = 2;
map_[2] = 3;
map_[3] = 4;
for( std::map<int, int>::iterator iter = map_.begin();
     iter != map_.end();
     ++iter )
{
    std::cout << iter->second;
}

これは234を出力することが保証されていますか、それとも実装定義ですか?


実際の理由:intキーを持つstd::mapがあります。非常にまれな状況では、具体的なint値よりも大きいキーですべての要素を反復処理したいと思います。うん、std::vectorがより良い選択のように聞こえますが、私の「非常にまれな状況」に注意してください。


EDITstd::mapの要素はソートされていることを知っています。それを指摘する必要はありません(ほとんどの回答について)。私も質問に書きました。
コンテナを反復処理するときに、反復子と順序について尋ねていました。 @Kerrek SBに答えてくれてありがとう。

145
Kiril Kirov

はい、それは保証されています。さらに、*begin()は、比較演算子によって決定される最小要素と*rbegin()最大要素を提供し、式!compare(a,b) && !compare(b,a)が真である2つのキー値abは等しいと見なされます。デフォルトの比較関数はstd::less<K>です。

順序付けは幸運なボーナス機能ではありませんが、2つのキーが同じ場合(上記の規則により)を決定し、効率的なルックアップ(本質的にバイナリ)を実行するために使用されるため、データ構造の基本的な側面です検索、要素数に対数的複雑さがある)。

162
Kerrek SB

これは、C++標準の連想コンテナ要件によって保証されています。例えば。 C++ 11の23.2.4/10を参照:

連想コンテナのイテレータの基本的なプロパティは、
キーの非降順でコンテナを反復処理することです。
非降順は使用された比較によって定義されます
 iからjまでの距離が
 positive、
 value_comp(* j、* i)== false 

および23.2.4/11

一意のキーを持つ連想コンテナの場合、より強い条件が保持されます。
 value_comp(* i、* j)!= false。
41

データ構造に混乱があると思います。

ほとんどの言語では、mapは単なるAssociativeContainerであり、キーを値にマップします。 「新しい」言語では、これは一般にハッシュマップを使用して実現されるため、順序は保証されません。

ただし、C++では、これはそうではありません。

  • std::mapソート済み連想コンテナです
  • std::unordered_mapは、C++ 11で導入されたハッシュテーブルベースの連想コンテナです

したがって、注文の保証を明確にするために。

C++ 03の場合:

  • std::setstd::multisetstd::mapおよびstd::multimapは、キー(および指定された基準)に従って順序付けられることが保証されています
  • std::multisetおよびstd::multimapでは、標準は同等の要素(つまり、等しいと比較する要素)に順序保証を課しません

C++ 11の場合:

  • std::setstd::multisetstd::mapおよびstd::multimapは、キー(および指定された基準)に従って順序付けられることが保証されています
  • std::multisetおよびstd::multimapでは、標準は、同等の要素(等しいと比較する要素)が挿入順序に従って順序付けられることを課します (最初に挿入された最初)
  • std::unordered_*コンテナは、名前が示すとおり、順序付けされていません。最も注目すべきは、コンテナの変更時(挿入/削除時)に要素の順序が変更される可能性があることです。

要素が何らかの方法で順序付けられていると規格が言っている場合、それは次のことを意味します。

  • 反復すると、定義された順序で要素が表示されます
  • 逆に反復すると、要素が逆の順序で表示されます

これで混乱が解消されることを願っています。

29
Matthieu M.

これは234を出力することが保証されていますか、または実装が定義されていますか?

はい、std::mapはソートされたコンテナであり、KeyComparatorの順に並べられています。保証されています。

具体的なint値よりも大きいキーを使用して、すべての要素を反復処理したいと思います。

それは確かに可能です。

4
jpalecek

はい... std::mapの要素は厳密な弱い順序を持っています。つまり、要素はセットで構成されます(つまり、「等しい」キーの繰り返しはありません)。任意の2つのキーAおよびBをテストして、キーAがキーBより小さくなく、BがAより小さくない場合、キーAはキーBと等しいことを決定します。

そうは言っても、その型の弱い順序があいまいな場合は、std::mapの要素を適切に並べ替えることができません(キー型として整数を使用している場合は問題ありません)。 std::mapのキーに使用している型の合計順序を定義する操作を定義できる必要があります。そうしないと、Aのプロパティを持つ要素またはポーズの順序が半順序になります。このシナリオで一般的に起こるのは、キー/値のペアを挿入できることですが、マップ全体を反復処理すると、キー/値のペアが重複する可能性があります。または、マップ内の特定のキー/値ペアのstd::map::find()を実行しようとしたときに、「欠落」キー/値ペアを検出します。

3
Jason