22

C ++のコンテナ、、vector...dequeは、コンテナ要素へのアクセスat(index)に加えて、アクセサ関数を提供します。operator[index]

このメンバー関数とメンバー演算子関数operator[]の違いは、deque :: atは、out_of_range例外をスローすることにより、要求された位置が範囲外であるかどうかを通知することです。

C ++コードでは範囲外の可能性のある要素にアクセスすることは意味がないため、コードでこの関数が必要になったことがありません。コードは常に正しいインデックスにアクセスするように記述されています(または、インデックスを一致させることができない場合に意味のあるエラー/例外を生成します)。

at()本番コードで使用されている実際の例(おそらく、いくつかのコンテキストを追加するため、いくつかのオープンソースプロジェクトから)に興味があります。

at()たぶん誰かが、使用が理にかなっているアルゴリズム問題の例をあげることができます。

注:最近、いくつかの単体テストコードで使用しました。ここでは、インデックスチェックコードを追加することは問題の価値があるとは見なされず、によってスローされるout_of_range例外at()は、テストが失敗した場合に備えて十分なinfo+contextと見なされます。

注:ildjarnによるこの回答について-私はこれについて議論を始めたり、戦争についてコメントしたりしたくありません。私は「ポジティブ」な発見、つまりそれが使用された具体的な例に興味があります。ありがとうございました。

4

8 に答える 8

13

使用されているインデックスを制御しない場合(コードのクライアントから渡された場合など)、手動で範囲内にあるかどうかを確認するか、を使用atして例外を報告する必要があります(独自のエラー報告で呼び出し元をキャプチャして通知するか、標準の例外を上方に伝播することができます)。

言い換えると、入力パラメーターをチェックするのは呼び出された関数の責任ですが、これをifステートメントで明示的に行うのか、at代わりにを使用して暗黙的に[]行うのかは議論の余地があります。とにかく例外をスローするout_of_rangeだけの場合(渡されたインデックスがコレクションのサイズ以上の場合)、atそれを実行してコーディングを節約できると思います。

不良データをサイレントに返すことは、ほとんどの場合、最善の解決策ではありません。4要素の整数デッキに対してx[7]を単純に返す場合の問題は、呼び出し元がそれを有効なゼロと見なすことです。そうではありません

于 2011-04-13T07:26:27.913 に答える
7

私の意見でat()は、これは100%役に立たないメンバー関数です。標準ライブラリコンテナの有効な範囲内でのみアクセスすることは、そのコンテナを使用するための前提条件であり前提条件の違反はassert、例外をスローするのではなく、処理する必要があります。の存在は、コンテナがその前提条件/不変条件を維持するのに役立つことは決してなく、実際には、適切な境界チェックアクセスが前提条件ではないようat()に見せることによって問題を混乱させるだけです。

つまり、最終的にプログラマーのエラーによってのみ引き起こされる可能性のあるものに例外をスローすることは、ばかげたことを超えています。より詳細な説明、特にD. Abrahamsによる投稿については、このスレッドを参照してください。長い間、読む価値はあります:comp.lang.c ++。moderated:Exceptions

編集: OPの追加されたメモに応じて明確にするために、C ++での私の経験では、専門的、オープンソース、その他の方法で、標準のコンテナーの使用に遭遇したことは一度もないと言っていますat()。実際、本番コードでは使用されていません。さらなるコメントや詳細は、なぜそうだと思うのかを合理化するためだけのものでした。

于 2011-04-13T07:22:01.410 に答える
6

私が一貫してat()役立つと思ったユースケースの1つは、複雑なユーザー入力の解析を容易にすることです。たとえば、C ++コードを分析するとき、文法構造をチェックするときに、字句トークンの配列に沿って移動していることに気付きます。ロジックは、「このトークンが識別子で、次のトークンが等しい場合は割り当てである必要があるため、セミコロントークンを先にスキャンして、式のトークン範囲を確立する」のようなものです。このat()ようなコードで使用すると、現在のポイントから少し離れた場所で期待を簡単に表現できます。

if (tokens.at(i) == Switch)
{
    if (tokens.at(++i) != Left_Parentheses)
        // throw or return to say input program's broken...
    if (tokens.at(++i) == ...)
        ...
}

無効なプログラムを解析しようとすると、例外が発生します。位置のインクリメントはコード全体の非常に多くの場所で発生するため、サイズを継続的に再確認することは悪夢になります(冗長で非常にエラーが発生しやすい)。このような状況では、プログラムが有効であるために必要な大きさがどれだけ大きいかを理解するだけです。文法規則が適用されます。ここでの使用at()は、機能的に同等の代替手段と比較して、簡潔で、堅牢で、直感的で、適度にパフォーマンスが高くなります。

FWIW-私たちの製品コード(200k行、ほとんどはチームに参加する前に書かれたもの)をすばやく検索すると、の使用法が12個見つかりましたat()

于 2011-04-15T02:23:52.233 に答える
5

私の場合はむしろそうです:なぜそれを使用しないのですか?

アプリケーションのパフォーマンスが重要な部分にいる場合を除いて、未定義動作std::out_of_rangeには常に賛成する必要があります。少なくともそれが私の信条です。

実際には、私は通常、チェックされたアクセスを使用するように作業しているすべてのコードを変換します。パフォーマンスの低下はほとんどのコードで目に見えません。少なくともcatch(std::exception const&)、コードが失敗することがあるメモリの破損ではなく、実行の現在のコンテキスト(ルートレベルで生成された)に関する情報を含む素晴らしいレポートがあります。後で(またはさらに悪いことに、それが機能したように見えます)。

入力を何よりもまず検証する必要があることに同意します。事前にアクセスを確認する必要があることに同意します...ただし、忘れた場合やバグがあった場合に備えて、を用意しておくことをお勧めしますat()

[]代わりに使用することat()は、ポケットにセキュリティがない/ある(または)装填済みの銃を運ぶようなものです。装着するのを忘れることができますが、喜んで取り外しますか?それは狂気です。

于 2011-04-13T09:42:30.123 に答える
4

簡単に検索したところ、特にInkscape(svgエディター)、Google v8、Android、Chromium、Ogreがこの機能を使用していることがわかりました。この(初歩的な)リストは、正規表現を使用した単純なグーグル検索at\([0-9]+\)から取得されました。

\.at\([0-9a-z_]+\)前の式の代わりに使用すると、より一般的な結果が得られ、 OpenJdkと豊富なsourceforgeプロジェクトが追加されます。

于 2011-04-13T10:55:03.777 に答える
0

v.at(-1)のように失敗することはありませんv[-1](例外が発生します)

于 2011-04-13T10:26:03.740 に答える
0

at私はここの多くの人々がほとんど役に立たないことに同意します。ただし、コンテナ(またはコンテナのリスト)へのポインタを操作すると、見栄えが良くなる場合があります。

std::vector<std::vector<int> >::iterator i;
for (i = v2.begin(); i != v2.end(); ++i)
{
    int x1 = (*i)[3]; // UGLY
    int x2 = i->at(3); // Looks OK
}

を使用すると、このコードの方が見栄えがよいと思いますat

于 2011-04-13T16:53:02.910 に答える
0

Stroustrupはat、インデックスが有効な範囲内にあることが確実な場合を除いて、すべての場所で使用することをお勧めします。

彼は、以下のようなコードには[]演算子を使用できることをお勧めします。

for (int i = 0; i < v.size(); ++i)
{
    // use v[i] - we are sure it will be a valid index
}

その他の場合は、at

于 2012-11-22T02:40:40.927 に答える