web-dev-qa-db-ja.com

数値を追加するだけでイテレータをインクリメントできますか?

イテレータで通常の計算を行うことはできますか?つまり、数値を追加するだけでそれをインクリメントできますか?

例として、要素vec[3]を削除したい場合、これを実行できますか?

std::vector<int> vec;
for(int i = 0; i < 5; ++i){
      vec.Push_back(i);
}
vec.erase(vec.begin() + 3); // removes vec[3] element

それは私(g ++)で動作しますが、動作するかどうかは保証かわかりません。

43
Frank

イテレーターがランダムアクセスイテレーターである場合に機能します(ベクターのイテレーターは reference を参照)。 STL関数 std::advance は、一般的なイテレータを進めるために使用できますが、イテレータを返さないため、見た目がきれいであるため、可能であれば+を使用する傾向があります。

C++ 11ノート

std::next および std::prev 、これはdoがイテレータを返すため、テンプレートランドで作業している場合は、それらを使用して汎用イテレータを進めても、クリーンなコードを保持できます。

48
Todd Gardner

微妙な点は、operator+Distanceを取ることです。つまり、符号付き整数です。符号なしでイテレータをインクリメントすると、精度が失われ、驚かれる可能性があります。たとえば、64ビットシステムでは、

std::size_t n = (1 << 64) - 2;
std::vector<double> vec(1 << 64);
std::vector<double> slice(vec.begin() + n, vec.end());

実装定義の動作につながります。 g++またはclangを使用すると、正規の-Wsign-conversionまたは-Wallの一部ではない警告フラグ-Wextraを使用して、このような望ましくない変換について警告するようコンパイラーに要求できます。

回避策は、ポインタを直接操作することです

std::vector<double> slice(vec.data() + n, vec.data() + vec.size());

それはきれいではありませんが、正しいです。場合によっては、イテレータを手動で作成する必要があります。たとえば、

std::vector<double>::iterator fromHere{vec.data() + n};
vec.erase(fromHere, vec.end());
2
Fred Schoen

ランダムアクセスイテレータで動作します。一般に、より一般的な std :: advance を確認することをお勧めします。この関数テンプレートの使用によるパフォーマンスへの影響を必ず理解してください。

2