14

&*vector::end()は未定義の動作だと思っていました...いくつかの投稿がStroustrupのコードを参照しているのを見るまで:

void vector_pointer_test(element_t* first, element_t* last, int number_of_times) 
{ 
       vector<element_t> container(first, last); 
       // &*container.begin() gets us a pointer to the first element 
       sort(&*container.begin(), &*container.end()); 
       unique(&*container.begin(), &*container.end()); 
}

イテレータの逆参照はend()未定義の動作ですか、それとも有効ですか?

4

2 に答える 2

7

これは必ずしも未定義の動作ではありませんが、反復子の特定の実装に依存します。

C++03 24.1/5 反復子の要件

配列への通常のポインターが、配列の最後の要素を超えて指すポインター値が存在することを保証するのと同様に、どの反復子型にも、対応するコンテナーの最後の要素を超えて指す反復子値があります。これらの値は、過去の値と呼ばれます。式 *i が定義されている反復子 i の値は、逆参照可能と呼ばれます。ライブラリは、過去の値が逆参照可能であるとは想定していません。

container.end()逆参照可能でない場合、問題のコードは未定義の動作をします。多くの場合、ベクターの反復子は単なるポインターになります。そのような場合、未定義の動作はありません。

于 2012-08-01T02:25:51.130 に答える
3

未定義の動作です。つまり、C++ 標準で定義されていない動作です。実装によって定義される場合があります。より可能性が高いのは、ある状況ではたまたま機能し、別の状況では機能しないということです。

この場合、反復子が生のポインターであれば、コンパイラーはおそらく &*i をノーオペレーションに最適化するので、うまくいくでしょう。Stroustrup は、ベクトルが生のポインターを反復子として使用していることを知っていた可能性があります。

たとえコンパイラがそれを最適化しなくても、実際には、ベクトルのメモリがたまたまセグメント境界で終了するように割り当てられた場合にのみ失敗する可能性があります。(または、イテレータの実装が、デバッグ目的などで逆参照できないことをチェックするように書かれている場合。)

C++11 では、次のように記述します。

sort(container.data(), container.data()+container.size()); 
于 2012-08-01T12:01:29.287 に答える