2016-06-27 6 views
2

このコードで停止しますはどのようにリストを反復が、サイズ-1

for (std::list<point>::const_iterator it = controlPoints->begin(); 
    it != controlPoints->end(); 
    ++it) { 
    ... 
    } 

相当する:私は1つを得た場合

for (int i = 0; i < controlPoints->size; i++) { 
... 
} 

意味は、それがリストのすべての要素を反復処理です要素を繰り返します。

何に相当するであろう:私はどのようにイテレータを使用してIループサイズ-1回することができ、

for (int i = 0; i < controlPoints->size-1; i++) { 
    ... 
    } 

を意味ですか?

答えて

9

明白な方法は、最後にイテレータを取得し、それをデクリメントすることです:

auto stop = controlPoints.end(); 
--stop; 

for (std::list<point>::const_iterator it = controlPoints->begin(); 
    it != stop; 
    ++it) { 
    ... 
    } 

あなたが優先場合はstd::advanceまたはstd::nextを使用することができますが、この場合のために、単純な減少で結構です。

+3

明示的に明記するだけで、 'it!= stop'条件がそのケースでは動作しないので、' list <> 'があらかじめ空でないことを確認してください(未定義の動作です)。 –

6

controlPoints->end()もイテレータです。

あなたはこれを行うことができます:

std::list<point>::const_iterator it = controlPoints->begin(); 
std::list<point>::const_iterator stop = controlPoints->end(); 
if (it != stop) for (--stop; it != stop; ++it) { 
    ... 
} 

より詳細なが、それはリストが0、1以上の要素を持っているかどうかを使用しても安全です。

ここで重要なのは、イテレータがインクリメントとすることができるということである(双方向イテレータ用)の位置を後退/前進させるためにデクリメントし、それはやっての同等です:あなたが求めるべきでC++ 11では

int it = 0; 
int stop = list.size(); 
if (it != stop) for(--stop; it < stop; ++it) { 
    ... 
} 
3

できるだけ頻繁にranged for forループを使用してください。 for(;;)ループは複雑でエラーが発生する傾向があります。

for(:)ループを使用すると、コードを書き留めた時点から複雑さが増しますが、そのインフラストラクチャを一度書き直して再利用することができるため、コード全体にわたってバグがなくなります。ここで、で開始する


は簡単range_tです:

template<class It> 
struct range_t { 
    It b, e; 
    It begin() const { return b; } 
    It end() const { return e; } 
    std::size_t size() const { return std::distance(begin(), end()); } 
    using iterator_tag = typename std::iterator_traits<It>::iterator_category; 
private: 
    static It safe_advance(It in, It bound, std::ptrdiff_t n, std::random_access_iterator_tag) const { 
    if (n == 0) return in; 
    if (n < 0) n = (std::min)(n, -std::distance(bound, in)); 
    if (n > 0) n = (std::max)(n, std::distance(in, bound)); 
    return std::advance(in, n); 
    } 
    static It safe_advance(It in, It bound, std::ptrdiff_t n, ...) const { 
    if (n == 0) return in; 
    while (n < 0 && in != bound) { 
     in = std::prev(in); --n; 
    } 
    while (n > 0 && in != bound) { 
     in = std::next(in); ++n; 
    } 
    return in; 
    } 
public: 
    range_t without_back(std::size_t n = 1) const { 
    return {begin(), safe_advance(end(), begin(), -(std::ptrdiff_t)n, iterator_tag{} }; 
    } 
    range_t without_front(std::size_t n = 1) const { 
    return {begin(), safe_advance(end(), begin(), n, iterator_tag{} }; 
    } 
    bool empty() const { return begin() == end(); } 
    decltype(auto) front() const { return *begin(); } 
    decltype(auto) back() const { return *std::prev(end()); } 
}; 
template<class It> 
range_t<It> range(It b, It e) { return {b,e}; } 
// rvalues blocked: 
template<class C, class It = decltype(std::begin(std::declval<C&>()))> 
range_t<It> range(C& c) { return range(std::begin(c), std::end(c)); } 

それはイテレータの範囲を格納し、反復可能そのものです。そして

auto r = range(*controlPoints).without_back(); 

は、最後の要素なしcontrolPointsある範囲のオブジェクトです。遠隔ベースを使用して

あなたがこれを行うことができますのために:上記のコードは慎重に空の配列を供給して処理する

for (auto& x : range(*controlPoints).without_back()) { 
} 

注意を。

イテレータのイテレータを使用できるようにする同様のアダプタを作成することもできます。私は通常Indexを保存して++==などを渡してindex_iteratorを書くことでこれを行います。 *を除いて、Indexのコピーが返されます。

これは、整数に反復子を作成するのに便利ですが、反復子に反復子を作成することもできます。

は、その後、あなたのコンテナ内のイテレータのインデックスの範囲を作成し、あなたは次のようになり、構文取得する:あなたがそれらを必要とする場合も、あなたのイテレータを与えるあなたは

for (auto it : iterators_into(*controlPoints)) { 
} 

与える範囲ベースのループを。

関連する問題