web-dev-qa-db-ja.com

'advance'関数なしで反復子の複数の位置を増やすことはできますか?

advance()関数を使用してイテレータをインクリメントできることを知っています。また、iterator++を使用して、イテレータを1ポジション増やします。なぜit+=2を使用できないのですか?

int main()
{
    list<int> l1{1, 2, 3, 5, 6};
    list<int> l2{2, 6, 8};
    auto it = l1.begin();
    advance(it, 2);         //works
    it++;                   //works
    // it+=2;                  //not work
    l2.splice(l2.begin(), l1, it);

    for(int a: l2) cout<<a<<" ";
    cout<<endl;

    return 0;
}

上記のコード here を実行できます。

16
Lusha Li

operator +=RandomAccessIterator でのみサポートされています。一定の複雑さを持つことになっていることに注意してください。

std::list の反復子は BidirectionalIterator であり、operator +=をサポートしません。 (std::vectorおよびstd::arrayの反復子はRandomAccessIteratorです。)

RandomAccessIteratorの複雑さが一定の場合、両方とも std :: advance で使用できることに注意してください。他のInputIterator(BidirectionalIteratorを含む)に使用される場合、複雑さは線形です。つまり、std::advanceを使用することは、より一般的であり、RandomAccessIteratorの利点を自動的に利用できるため、良いアイデアです。

30
songyuanyao

このイテレータでは+= 2を使用できません。一般的な場合、std::list<>イテレータを任意の値だけインクリメントすることは比較的非効率的操作であるためです。 +=は、コードでこの非効率的な操作を不注意に/知らずに使用することを防ぐために、イテレータータイプに対して定義されていません。代わりに、本当にそれをしたい場合は、std::advanceを使用することになっています。これは、非効率的なことをしている可能性があるという事実を強調することを目的とした「レッドフラグ」関数です。 std::advanceは、主にコードスケッチまたはngetly-to-get-executedフォールバックコードを対象としています。本番コードでstd::advanceを無償で使用することは想定されていません。突然std::advanceに依存していることに気付いた場合、おそらくデータ構造を再設計する必要があることを意味します。基本的に、std::advanceはキャストのようなものです。使用する非常に非常に適切な理由がない限り、避けてください。

または、std::nextを使用できます

it = std::next(it, 2);

この関数は、std::advanceよりもはるかに使いやすいです。デフォルトでは、この関数はイテレーターを1ステップ進めるように設計されていますが、2番目のパラメーターを指定してそれをさらに進めることができます。繰り返しますが、2番目のパラメーターの値が一定でなく潜在的に大きい場合、「レッドフラグ」関数と見なす必要があります。 2の定数値は間違いなく許容範囲内です。

15
AnT