web-dev-qa-db-ja.com

std :: map :: atを使用してマップ要素を取得する必要がある場合

私はウェブ上のさまざまな記事と stackoverflow で質問を読みましたが、私にとっては、_std::map::at_を使用してマップ要素を取得する方が良い場合があるかどうかは明確ではありません。

定義 、_std::map::at_に従って

キーkで識別される要素のマッピングされた値への参照を返します。

Kがコンテナ内のどの要素のキーとも一致しない場合、関数はout_of_range例外をスローします。

私にとっては、特定のキーを持つ要素が100%確実に存在するときに_std::map::at_を使用する価値がある場合のみです。そうでない場合は、例外処理を検討する必要があります。

  1. _std::map::at_が最も効率的でエレガントな方法と見なされるケースはありますか?どのような場合に_std::map::at_を使用することをお勧めしますか?
  2. そのようなキーを持つ要素を持たない可能性がある場合、map::find()を使用する方が良いと思いますか?そして、map::find()それはより速く、よりエレガントなアプローチですか?
_if ( map.find("key") != map.end() )
{
    // found 

} else
{
    // not found
}
_

p.s

_map::operator[]_は、要素が存在しない場合に挿入されるため、危険な場合があります。

編集済み:何らかの関係があるリンク リンク1リンク2リンクリンク4リンク5リンク6

44
T M

ここでのほとんどの既存の回答とは異なり、マップ内の要素の検索に関連する実際の4メソッドがあることに注意してください(_lower_bound_、_upper_bound_および_equal_range_、これらは精度が低い):

  • _operator[]_は、非constバージョンにのみ存在します。前述のように、存在しない場合は要素を作成します
  • C++ 11で導入されたat()は、存在する場合は要素への参照を返し、そうでない場合は例外をスローします
  • find()は、存在する場合は要素に反復子を返し、存在しない場合はmap::end()に反復子を返します
  • count()は、そのような要素の数を返します。mapで、これは0または1です

セマンティクスが明確になったので、次のどれを使用するかを確認しましょう。

  • エレメントがmapに存在するかどうか(のみ)を知りたい場合は、count()を使用します。
  • 要素にアクセスしたい場合、map内にある必要がある場合は、at()を使用します。
  • 要素にアクセスしたいが、mapにあるかどうかわからない場合は、find();を使用します。結果のイテレータがend()の結果と等しくないことを確認することを忘れないでください。
  • 最後に、要素が存在する場合はアクセスするか、存在しない場合は作成(およびアクセス)する場合は、_operator[]_を使用します。タイプデフォルトコンストラクタを呼び出して作成したくない場合は、insertまたはemplaceを適切に使用してください
59
Matthieu M.

要素が見つからなかった場合、std::map::at()は_out_of_range_例外をスローします。この例外は_logic_error_の一種の例外であり、私にとっては使用の観点からはassert()の類義語の一種です。違反のようなプログラムの内部ロジックのエラーを報告するために使用する必要があります論理的前提条件またはクラス不変量の。

また、at()を使用してconstマップにアクセスできます。

だから、あなたの質問のために:

  1. Constマップにアクセスするとき、および要素の不在が論理エラーであるときは、_[]_の代わりにat()を使用することをお勧めします。
  2. はい、要素がここにあるかどうかわからない場合はmap::find()を使用する方が良いです:この場合、それは論理エラーではないので、_std::logic_error_例外をスローしてキャッチすることはあまり洗練されたプログラミング方法ではありません、パフォーマンスについて考えなくても。
21
alexeykuzmin0

既に述べたように、マップ内の要素にアクセスするには3つの異なる方法があります:at()operator[]、およびfind()upper_boundlower_bound、およびequal_rangeもありますが、これらはより複雑な状況のためです次/前の要素を見つけたい場合など)

だから、いつどれを使うべきですか?

operator[]は基本的に「存在しない場合は、デフォルトで構築されたマッピングされた要素で作成します」です。つまり、スローされないことを意味します(メモリ割り当てがスローされるコーナーケース、またはキーまたは値コンストラクターがスローされるコーナーケースを除く)。 。

at()は、そのキーの要素がない場合にスローされます。通常のプログラムフローには例外を使用しないでください。したがって、at()を使用することは、「そのような要素があると確信しています」と言っています。ただし、間違っている場合は例外(未定義の動作ではない)を受け取るという追加の利点があります。要素が存在することに自信がない場合は、これを使用しないでください。

find()は「そのような要素がある場合とない場合があるので、見てみましょう...」と言い、両方のケースに異なる反応をする可能性を提供します。したがって、より一般的なアプローチです。

12
Arne Mertz

findoperator[]、およびatの3つすべてが便利です。

  • findは、誤って要素を挿入したくない場合に適していますが、要素が存在する場合にのみ動作します。

  • atは、何かがマップ上にあるはずであり、そうでなければ例外をスローする場合に適しています。 constよりも簡潔な方法でfindマップにアクセスすることもできます(op[]を使用できない場合)

  • op[]は、wantがデフォルトの要素を挿入する場合に適しています。たとえば、最初に検出されたすべてのWordに対してint 0を挿入するWordカウントプログラムの場合イディオムwords[Word]++;)。

5

これは、この機能の要件とプロジェクトの構成方法によって異なります。オブジェクトを返すことになっていて、見つからなかったためにできない場合は、その処理方法に関する2つのオプションがあります。例外を介して、または何も見つからなかったことを意味するある種のセンチネルを返すことができます。例外をスローする場合は、at()を使用してください。例外がスローされます。例外をスローしたくない場合は、find()を使用して、センチネルオブジェクトを返すためだけに例外を処理する必要がないようにします。

3
NathanOliver

ユースケース次第だと思います。 std::map::at()の戻り値の型は、見つかった要素の値への左辺値参照ですが、std::map::find()は反復子を返します。あなたが好むかもしれません

_return myMap.at("asdf"s) + 42;
_

より精巧な表現で

_return myMap.find("asdf"s)->second + 42;
_

式でstd::map::at()の結果を使用するときはいつでも、要素が存在することを期待し、欠落している要素をエラーと見なします。したがって、例外はそれを処理するための適切な選択です。

3
cdonat

map :: at()はl値の参照を返します。参照で戻ると、メソッドチェーンなどの利用可能なすべての利点を使用できます。

例:

  map<int,typ> table;
  table[98]=a;
  table[99]=b;

  table.at(98)=table.at(99);

operator[]も参照によってマップされた値を返しますが、キーの検索が見つからない場合は値を挿入できます。その場合、コンテナーのサイズは1ずつ増加します。

イテレータの無効化 を処理する必要があるため、これには注意が必要です。

そのようなキーを持つ要素を持たない可能性があるときにmap :: find()を使用する方が良いと思いますか? map :: find()より高速でエレガントなアプローチですか?

はい、意味的には、要素の存在がわからないときにfind()を使用するのが理にかなっています。初心者でもコードを理解しやすくします。

時間効率に関しては、マップは一般にRBツリー/バランスの取れたバイナリ検索ツリーとして実装されるため、複雑さはO(logN) for find()になります。

C++仕様:

T&operator [](const key_type&x);
効果:マップにxに相当するキーがない場合、value_type(x、T())をマップに挿入します。必須:key_typeはCopyInsertableで、mapped_typeはMUST DefaultInsertableを* thisに戻す戻り値:* thisのxに対応するmapped_typeへの参照4複雑さ:対数。

T&at(const key_type&x);
const T&at(const key_type&x)const;戻り値:* thisのxに対応するmapped_typeへの参照。スロー:そのような要素が存在しない場合、out_of_range型の例外オブジェクト。複雑さ:対数。

2
basav

違いはセマンティクスだと思います。

std::map::at()は私のマシンでは次のようになります。

_mapped_type&
at(const key_type& __k)
{
    iterator __i = lower_bound(__k);
    if (__i == end() || key_comp()(__k, (*__i).first))
        __throw_out_of_range(__N("map::at"));
    return (*__i).second;
}
_

ご覧のとおり、_lower_bound_を使用し、end()をチェックし、キーを比較し、必要に応じて例外をスローします。

find()は次のようになります。

_iterator
find(const key_type& __x)
{ return _M_t.find(__x); }
_

ここで、__M_t_は、実際のデータを格納する赤黒ツリーです。明らかに、両方の関数は同じ(対数)複雑さを持っています。 find() + end()のチェックを使用すると、atとほぼ同じことを実行しています。セマンティックの違いは次のとおりです。

  • 特定の場所に要素が必要なときにat()を使用し、そこにあると想定します。この場合、目的の場所にない要素の状況は例外的であるため、at()は例外をスローします。
  • マップ内で要素を見つける必要がある場合は、find()を使用します。この場合、要素が存在しない状況は正常です。また、find()は値を取得する以外の目的で使用できるイテレータを返すことに注意してください。
2
SingerOfTheFall