11

イテレータを取るコードを書きましたが、逆の順序で比較を行う必要があります。

template<class ConstBiIter>
bool func(ConstBiIter seq_begin, ConstBiIter seq_end)
{
    ConstBiIter last = std::prev(seq_end);
    while (--last != std::prev(seq_begin)) // --> I need to compare the beginning data
    {
        ......
    }
    return true;
}

VS2013 では、デバッグ モードで実行--last != std::prev(seq_begin)すると、デバッガ アサーションがエラー メッセージで失敗します。

Expression:string iterator + offset out of range.

しかし、Release モードでは境界チェックがないため、Release モードで実行して正しい結果が得られれば問題ありません。

私の質問は次のとおりです。

  1. std::prev(some_container.begin())歩哨として安全に使用できsome_container.rend()ますか?

  2. reverse_iteratorと を直接比較するにはどうすればよいiteratorですか? 私がコードを書いた場合: std::cout << (std::prev(some_container.begin())==some_container.rend()) << std::endl;コンパイルしてもコンパイルされませんreinterpret_cast

物理的prev(some_container.begin())に等しいかどうか興味がありますか?some_container.rend()

4

3 に答える 3

11

いいえ、begin イテレータをデクリメントしようとするのは安全ではありません。

std::reverse_iterator(これは によって返されるものですstd::rend) 実際には、開始イテレータの前にイテレータが含まれていません。概念的に指している要素の次の要素への基になる反復子を格納します。したがって、リバース イテレータが「終わりの 1 つ後」(つまり「始まりの前」) の場合、その基になるイテレータ ( を呼び出して取得base()) は開始イテレータです。

于 2014-08-12T12:02:07.267 に答える
7

未定義の動作は、現在テストで機能していても安全ではありません。C++ では、「試してみたらうまくいった」ということは、それを正しく行っているという良い証拠にはなりません。未定義の動作の最も一般的なタイプの 1 つは、「うまくいったように見える」というものです。

問題は、未定義の動作が根本的に壊れやすいことです。強く息を吹きかけると壊れます。

コンパイラは、未定義の動作を介してのみ到達する分岐とコードを自由に最適化し、多くの場合、それを実行します。サービス パッチ、コンパイラのアップグレード、コンパイラに渡されるフラグの一見無関係な変更、または実行可能パス名の長さの後でも、自由に行うことができます。99.9% の時間は問題なく動作し、残りの 0.1% の時間でハード ドライブをフォーマットできます。

これらのいくつかは、他のものより可能性が高いです。

std::string要素への反復子std::vectorはリリースでは基本的にポインターであり、コンパイラーは反復子となるポインターを型定義することさえできますが、次のコンパイラー バージョンがラップされたポインターを使用する場合、その仮定でさえ失敗する可能性があります。

C++ 標準には未定義の動作が残されているため、コンパイラの作成者はより最適なコードを自由に生成できます。あなたがそれを呼び出すと、あなたは彼らのつま先を踏むことができます.

そうは言っても、C++ 標準で定義されていない動作を使用する理由があります。そうするときは、それをしっかりと文書化し、分離し、その見返り (たとえば、デリゲートが の 2 倍の速さstd::function) が価値があることを確認してください。

上記は分離されておらず、特に未定義の動作なしで解決できるため、未定義の動作を行う価値はありません。

逆方向に反復したい場合の最も簡単な解決策は、いくつかの逆反復子を作成することです。

template<class ConstBiIter>
bool func(ConstBiIter seq_begin, ConstBiIter seq_end)
{
  std::reverse_iterator<ConstBiIter> const rend(seq_beg);
  for (std::reverse_iterator<ConstBiIter> rit(seq_end); rit != rend; ++rit)
  {
    ......
  }
  return true;
}

rfirst範囲を後方に反復するようになりました。

何らかの理由で同じ要素を参照する前方反復子に戻る必要があり、そうでない場合はrend、できますstd::prev(rit.base())。そのrit == seq_end時点で、それは未定義の動作です。

于 2014-08-12T14:08:43.007 に答える
1

24.5.1 逆反復子

クラス テンプレート reverse_iterator は、基になる反復子によって定義されたシーケンスの末尾からそのシーケンスの先頭まで反復する反復子アダプターです。逆方向反復子とそれに対応する反復子 i の間の基本的な関係は、恒等式 &*(reverse_iterator(i)) == &*(i - 1) によって確立されます。

于 2014-08-12T12:39:30.397 に答える