次の例に関して 2 つの質問があります。1)
std::vector<int> v(5,1);
cout << *v.end();
印刷結果は未定義です(コンパイラに依存します)
2)
int x = 5,y = 6;
std::vector<int*> pv;
pv.push_back(&x);
pv.push_back(&y);
cout << *pv.end();
出力結果は未定義 (コンパイラに依存) か NULL か
にアイテムがありませんend()
。これは、ベクター内の最後の有効なアイテムの直後のイテレータです。
*v.end();
これは未定義の動作です。end()
最後のアイテムの後のアイテムを指しているかどうかにかかわらず、イテレータを比較するために使用できます。
最後のアイテムの値にアクセスする簡単な方法はback()
、たとえば次のとおりです。
cout << v.back();
反復子は、コンテナーの最後の要素の1 要素後のend()
位置を指します。それが指すデータにアクセスすると、未定義の動作が呼び出されます。これは、両方の例に当てはまります。
まず、どちらの場合も動作は未定義です。未定義の「印刷結果」ではないことに注意してください。あなたのコードは、何も印刷する機会すらありません。終了イテレータに単に*
演算子を適用すると、すでに未定義の動作が発生します。例えばこれだけ
*v.end();
はすでに未定義の動作です。
第二に、この場合の未定義は「コンパイラに依存する」という意味ではありません。実装定義の動作はコンパイラに依存します。未定義は、同じコンパイラを使用している場合でも、「完全に予測できない」ことを意味します。
PS いくつかの密接に関連する問題に関して、標準委員会で進行中の作業が少しあるようです。
http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#208
http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#1213
うまくいけば、過去のイテレータにとって何が合法で何がそうでないかについて、より明確な仕様が得られることを願っています。しかし、一般的なケースでは、末尾イテレータが合法的に単数イテレータになる可能性があることは明らかです。つまり、一般的なケースでは逆参照できない可能性があります。
はい、どちらも未定義です。