2016-07-21 5 views
25

私は多くの時間を見てきましたstd::string::operator[]は境界チェックをしません。 2013年に尋ねられたWhat is the difference between string::at and string::operator[]?でも、operator[]は境界チェックを行わないと答えています。これでC++ 11以降ではstd :: string :: operator [] do bounds checkingですか?

私の問題は、私は[string.access]で(この場合はdraft N3797で)標準を見れば、我々は

const_reference operator[](size_type pos) const; 
reference operator[](size_type pos); 
  1. を持っている必要: pos <= size()
  2. 戻り値:*(begin() + pos)pos < size()の場合。それ以外の場合は、値charT()のタイプcharTのオブジェクトへの参照を返します。オブジェクトを変更すると、未定義の動作になります。
  3. 例外: Nothing。
  4. 複雑度:一定時間。

これはoperator[]は、それが文字列またはデフォルトcharTの要素を返す必要があるかどうかを判断するために境界チェックのいくつかの並べ替えを行う必要があることを信じるように私をリード。この仮定は正しいですか?今すぐ境界チェックを行うにはoperator[]が必要ですか?

+0

'std :: basic_string :: operator []'は境界チェックをしていないだけでなく、それに準拠するために境界チェックを行うことはできません。標準では、特に**この関数は**何もスローしていないと言います。 –

+7

@DavidHammen境界チェックを行うために何かを投げなければなりませんか?適合する実装が 'pos> = size()'をチェックし、それが必要なら 'charT()'を返すことができませんでしたか? – NathanOliver

+3

@DavidHammen: 'exit()'はスローしておらず、標準に準拠しています。 –

答えて

43

文句は少し混乱しますが、詳細を勉強すれば、実際には非常に正確です。

それはこのことを言う:

  • 前提条件が[]への引数は= Nであるか、またはそれは< Nだということです。
  • その前提条件を仮定すると、満足している:
    • それは< Nだ場合、あなたはあなたが尋ねた文字を取得します。
    • "それ以外の場合"(つまり、nの場合)は、charT()(ヌル文字)となります。

しかし、誰のルールは、あなたが前提条件を破るときのために定義されていない、と= Nためチェックが暗黙的に満足することができます(ただし、明示的であることを義務化されていない)、実際にcharT()を格納することにより、位置n

実装では、&hellipの境界チェックを実行する必要はありません。普通のものはそうしないでしょう。

+7

* "前提条件を破るときにルールは定義されていません" *おそらくあなたの答えの中で最も重要な部分です;) – Holt

+0

@Holt:Almost; OPは実際には、 "otherwise"節が境界チェックなしでどのようにトリガされるかを尋ねています! –

+1

私は別の前提条件によって立ち上がってしまいます。残りの部分が何であるかにかかわらず、UBを破ることを覚えておく必要があります。ありがとう。 – NathanOliver

1

http://en.cppreference.com/w/cpp/string/basic_string/operator_at

指定された場所posの文字への参照を返します。 いいえ 境界チェックが実行されます。

(強調鉱山)。

あなたは境界チェックしたい場合は、std::basic_string::at

に標準を使用する実装は、それは基本的に未チェックの配列アクセスが何を記述しているので境界チェックを提供する必要があります示唆しています。

境界内にアクセスすると、定義されます。外に出ると、未定義の振る舞いを引き起こします。

+8

標準に照らして非標準のウェブサイトを引用することは、証拠ではありません。 – Yakk

+3

@Yakk標準に準拠しているかどうかを確認するために、間違いなくデューディリジェンスが行われていると評価されている評価の高いリファレンスサイトを引用していますが、それは証明ではありませんが、答えの半分は正しいです。 – PSkocik

+0

標準では、境界チェックの必要性を暗示していませんが、実装者はn <= size()のコードを書くだけでよいことがはっきりと分かります。それ以外は未定義の動作であり、チェックは必要ありません。 – kfsone

2

この標準コンテナの演算子は、通常の配列の演算子[]の動作をエミュレートします。だからそれは何のチェックもしない。しかし、デバッグモードでは、対応するライブラリがこのチェックを提供することができます。

インデックスを確認する場合は、メンバー関数at()を代わりに使用してください。

14

operator[]

いいえ、それはしていません...決定するために境界チェックのいくつかの並べ替えを行います。前提条件付き

必須:pos < = size()。

それだけそれは常に文字列の要素を返すことができるというをとることができます。この条件が満たされない場合:未定義の動作。

operator[]は、ポインタを文字列の先頭からposだけインクリメントします。文字列が短い場合は、文字列の後ろのデータへの参照を返すだけです。シンプルなC配列の古典的な範囲外のように。

pos == size()の場合には、内部文字列データの末尾に余分にcharTを割り当てることができます。チェックを行わずにポインタをインクリメントするだけで、前述の動作を引き続き実現できます。

+0

'pos == size()'は質問されているケースでUBとは関係がないので、質問に答えてくれないようです! –

+0

ええ、それを忘れて追加しました。あなたの答えは私のものより優れています(私は+ 1だったでしょうが)多分複数のスタイルの回答が役立ちます。 – Superlokkus

4

まず、requires句があります。 requires節に違反した場合、プログラムは定義されていない方法で動作します。それはpos <= size()です。

したがって、言語はその場合に起こることだけを定義します。

次の段落では、pos < size()の場合、文字列内の要素への参照を返します。 pos == size()の場合、charT()という値を持つデフォルトの構成charTへの参照を返します。

これは境界チェックのように見えるかもしれませんが、実際にはstd::basic_stringは尋ねたものより1大きいバッファを割り当て、最後のエントリにcharT()を設定します。そうすれば、[]は単純にポインタを転送します。

私はその実装を避ける方法を考え出しました。標準はそれを強制するものではありませんが、私は自分自身に代わりが存在するとは確信できませんでした。 .data()で迷惑をかける何かがあり、単一のバッファを避けることが困難でした。

関連する問題