如何迭代向量?

时间:2015-07-17 15:04:24

标签: c++ vector iterator

我需要严格按照元素被推回到它的顺序迭代一个向量。对于我的特殊情况,最好使用迭代器,而不是迭代for-each循环,如下所示:

std::vector<int> vector;
for(int i = 0; i < vector.size(); i++)
   //not good, but works

我的问题是,是否可以通过迭代器迭代迭代器:

std::vector<int> v;
for(typename std::vector<int>::iterator i = v.iterator(); i != v.end(); i++)
   //good, but I'm not strictly sure about the iterating order.

那么,我可以根据我的要求安全地使用迭代器吗?它是否是标准化的?

3 个答案:

答案 0 :(得分:3)

如果您可以访问C ++ 11,则可以使用基于范围的for循环

for (auto i : v)

否则您应该使用begin()end()

for (std::vector<int>::iterator i = v.begin(); i != v.end(); ++i)

您还可以使用std::beginstd::end(这些也需要C ++ 11)

for (std::vector<int>::iterator i = std::begin(v); i != std::end(v); ++i)

begin会将迭代器返回向量中的第一个元素end会将迭代器返回到超过向量结尾的一个元素。因此,以这种方式迭代元素的顺序既安全又定义。

答案 1 :(得分:2)

如果你想使用迭代器,你的方法很好

for(auto it = v.begin(); it != v.end(); ++it)

迭代顺序实际上取决于容器和实际使用的迭代器。 对于std :: vector,此代码始终在向量中按顺序迭代元素。如果您使用v.rbegin()或v.rend()代替,则订单将被颠倒。 对于另一个容器,顺序是不同的,对于std :: set,相同的代码将按照排序标准的升序迭代元素。

答案 2 :(得分:1)

这是一个过于复杂的解决方案。

首先,我们从index类型开始。它可以存储任何模拟迭代器和/或积分的东西(基本上,支持+标量,delta到标量,复制,破坏和相等):

template<class T,
  class Category=std::random_access_iterator_tag,
  class Delta=decltype(std::declval<T>()-std::declval<T>())
>
struct index:
  std::iterator<Category, T, Delta, T*, T>
{
  T t;
  T operator*()const{ return t; }
  index& operator++(){++t; return *this;}
  index operator++(int){index tmp = *this; ++t; return tmp;}
  index& operator--(){--t; return *this;}
  index operator--(int){index tmp = *this; --t; return tmp;}
  T operator[](size_t i)const{return t+i;}
  friend bool operator<(index const& lhs, index const& rhs) {
    return rhs.t-lhs.t>0;
  }
  friend bool operator>(index const& lhs, index const& rhs) {
    return rhs<lhs;
  }
  friend bool operator<=(index const& lhs, index const& rhs) {
    return !(lhs>rhs);
  }
  friend bool operator>=(index const& lhs, index const& rhs) {
    return !(lhs<rhs);
  }
  friend bool operator==(index const& lhs, index const& rhs) {
    return lhs.t==rhs.t;
  }
  friend bool operator!=(index const& lhs, index const& rhs) {
    return lhs.t!=rhs.t;
  }
  friend Delta operator-(index const& lhs, index const& rhs) {
    return lhs.t-rhs.t;
  }
  friend index& operator+=(index& lhs, Delta rhs) {
    lhs.t+=rhs;
    return lhs;
  }
  friend index& operator-=(index& lhs, Delta rhs) {
    lhs.t-=rhs;
    return lhs;
  }
  friend index operator+(index idx, Delta scalar) {
    idx+=scalar;
    return idx;
  }
  friend index operator+(Delta scalar, index idx) {
    idx+=scalar;
    return idx;
  }
  friend index operator-(index idx, Delta scalar) {
    idx-=scalar;
    return idx;
  }
};

大部分都不需要,但我想完成。请注意,默认情况下,它声称是一个随机访问迭代器,但它的位置,因为它的引用类型不是引用。我觉得谎言值得。

使用index,我们都可以创建迭代器迭代器和迭代器迭代器。以下是我们如何创建迭代器迭代器:

using it_category=typename std::iterator_traits<It>::iterator_category;

template<class It, class Category=it_category<It>>
index<It, Category> meta_iterator( It it ) { return {it}; }

接下来,我们希望能够获取一些迭代器,并迭代范围。这意味着我们需要一个范围类型:

template<class It>
struct range {
  It b, e;
  range(It s, It f):b(s),e(f){}
  range():b(),e(){}
  It begin()const{return b;}
  It end()const{return e;}
  bool empty()const{return begin()==end();}
  template<class R>
  range(R&& r):range(std::begin(r),std::end(r)){}
};

这是一个特征,它采用可迭代范围(不仅是range,而且还有任何容器)并获取迭代器类型。请注意,一个优秀的ADL启用将是一个好主意:

template<class R>
using iterator=decltype(std::begin(std::declval<R&>()));

随机助手:

template<class R,class It=iterator<R>>
range<It> make_range(R&&r){ return {std::forward<R>(r)}; }
template<class It
range<It> make_range(It s, It f){return {s,f};}

这是一个有用的助手,可以解决我们的问题:

template<class R>
range<meta_iterator<iterator<R>> iterators_into( R&& r ){
  return {meta_iterator(std::begin(r)), meta_iterator(std::end(r))};
}

我们完成了:

std::vector<int> v;
for(auto it: iterators_into(v)) {
}

v的每个元素返回一个迭代器。

对于工业质量,你想要ADL改进的东西。此外,处理输入范围的右值存储使您可以在for(:)循环中更好地链接范围适配器。