4

この問題のより適切なタイトルが見つかりませんでした。必要に応じて、以下の質問に従って更新してください。

itera の要素を指すイテレータ - を考えてみましょうstd::vector<int>*iter次を使用して、現在のイテレータの位置にの値を挿入しています。

iter = target.insert(iter, *iter);

insert新しく挿入された要素にイテレータが返されることを理解しています。ここで、上記のステートメントを次のように変更しました。

iter = target.insert(iter, *iter++);

それがぎこちない動作になることはわかっていたので、Segmentation faultが発生しました。私が理解できないのは、上記の割り当てがどのように評価されるかです。つまり、その割り当て後にどの要素をiter指すかです。私が理解している限り、後置インクリメント演算子を使用したため、最初のステートメントと同様に動作するはずです。これは、以下のサンプル割り当てから推測しています。

i = i++;

上記の割り当ては の値に影響しないため、 のi場合も同様です*iter++

舞台裏での実際の行動は何ですか?


これは実際のコードです:

std::vector<int>::iterator begin = target.begin();

while (begin != target.end()) {
    if (*begin % 2 == 0) {
        begin = target.erase(begin);
    } else {
        begin = target.insert(begin, *begin); // I changed this line
        begin += 2;
    }
}

基本的に、上記のコードはベクトルから偶数要素を削除し、奇数要素を複製しています。

編集:

前の変更に加えて、2 行目を に変更すると++begin、現在のコードと同じように機能します。そこで、elseブロック内の 2 行を次の行に置き換えました。

begin = target.insert(begin, *begin++);
++begin;

そのため、前のケースよりも 1 つ後ろのイテレータを割り当てているようです。

だから、これは私がこの行動から理解したものです:

  • *begin++最初に を逆参照しbeginて、現在の場所の値を取得します。
  • beginポストインクリメント
  • ポストインクリメントのinsert後、反復子の前に逆参照された値を挿入するようになりました。したがって、元の の前に挿入するのbeginではなく、 の前に挿入し++beginます。そして、++begin挿入された場所に値を返します。

私はそれを正しく解釈しましたか?

4

2 に答える 2

3

私はあなたの質問をよく理解できませんでしたが、あなたがリストした理解に答えるために: あなたの理解は特定のコンパイラ/日/ビルドで正しいかもしれません. コンパイラは任意の順序で引数を評価する可能性があるため、 at orを挿入するかどうかは指定されていません(その結果、返される値は 2 つの異なる可能な値のいずれかになります) 。何が起こるかを正確に理解しようとするのではなく、コードを適切な部分に分割して、何をしようとしているのかを完全に明確にし、オプティマイザーに任せてください。ほぼ確実に、コア ダンプが発生した理由は、2 ずつインクリメントすると、スキップ オーバーし、コンテナーの最後を通過したことが検出されないためです。beginbegin + 1insertinsertend

begin = target.insert(begin, *begin++);また、「幸いなことに」関数の引数の評価後にシーケンス ポイントがあること、または2 つの書き込みがあり、間にシーケンス ポイントがない未定義の動作になることも指摘しておく必要があると思いますbegin(たとえばi = i++、UB)。

于 2013-07-10T16:06:11.360 に答える
1

私の知る限り、 target.insert(iter, *iter++) を構築することは、「未定義の動作」につながるため、合法的な c++ ではありません。*iter++ は正当であり、左から右に評価されますが、関数呼び出しの引数が評価される順序は指定されていません。このような式を記述すると、プログラミング エラーになります。

正確には、あなたのコード

target.insert(iter, *iter++)

与えられたエイリアス

std::vector<int>::iterator cur = iter;
std::vector<int>::iterator next = iter + 1;

この2つの方法で評価できます

targets.insert(next, *cur);
++iter;

また

targets.insert(cur, *cur);
++iter;

正確なバージョンは、コンパイラ、OS、その他のコードなどの影響を受け、通常は指定されていません。

于 2013-07-10T16:05:06.383 に答える