使用'for'循环遍历C ++ Vector

时间:2012-10-03 05:50:18

标签: c++ coding-style for-loop iterator

我是C ++语言的新手。我已经开始使用向量,并注意到在我看到的所有代码中通过索引迭代向量,for循环的第一个参数总是基于向量。在Java中,我可以使用ArrayList执行类似的操作:

for(int i=0; i < vector.size(); i++){
   vector[i].doSomething();
}

我有没有理由在C ++中看不到这个?这是不好的做法吗?

13 个答案:

答案 0 :(得分:86)

你没有看到这种做法的原因是非常主观的,并且没有明确的答案,因为我看到许多代码使用你提到的方式而不是iterator样式代码。

以下可能是人们不考虑vector.size()循环方式的原因:

  1. 每次在循环中调用size()都是偏执狂 条件。然而,要么它不是一个问题,要么它可以是微不足道的 固定
  2. 首选std::for_each()循环{/ 1}}
  3. 稍后将容器从for更改为其他容器(例如 std::vectormap)也会要求更改循环机制, 因为不是每个容器都支持list循环风格
  4. C ++ 11为在容器中移动提供了良好的便利。这被称为&#34;基于循环的范围&#34; (或#34;增强了for循环&#34;在Java中)。

    使用少量代码,您可以遍历完整(强制性!)size()

    std::vector

答案 1 :(得分:77)

  

我有没有理由在C ++中看不到这个?这是不好的做法吗?

没有。这不是一个坏习惯,但它会使您的代码具有某种灵活性

通常,在C ++ 11之前,迭代容器元素的代码使用迭代器,如:

std::vector<int>::iterator it = vector.begin();

这是因为它使代码更加灵活。

所有标准库容器都支持并提供迭代器,并且如果在以后的开发阶段需要切换另一个容器,则不需要更改此代码。

注意:编写适用于每个可能的标准库容器的代码并不像看起来那样容易。

答案 2 :(得分:67)

迭代向量的最简洁方法是通过迭代器:

for (auto it = begin (vector); it != end (vector); ++it) {
    it->doSomething ();
}

或(相当于上述)

for (auto & element : vector) {
    element.doSomething ();
}

在C ++ 0x之前,你必须用迭代器类型替换auto并使用成员函数而不是全局函数begin和end。

这可能就是你所看到的。与您提到的方法相比,优势在于您不会严重依赖vector的类型。如果将vector更改为其他“集合类型”类,则代码可能仍然有效。但是,您也可以在Java中执行类似的操作。概念上没有太大差异;但是,C ++使用模板来实现它(与Java中的泛型相比);因此,该方法适用于定义beginend函数的所有类型,即使对于静态数组等非类类型也是如此。见这里:How does the range-based for work for plain arrays?

答案 3 :(得分:32)

正确的方法是:

for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
    it->doSomething();
 }

其中T是向量内类的类型。例如,如果该类是CActivity,则只需编写CActivity而不是T.

这种方法适用于每个STL(不仅是矢量,它更好一点)。

如果您仍想使用索引,方法是:

for(std::vector<T>::size_type i = 0; i != v.size(); i++) {
    v[i].doSomething();
}

答案 4 :(得分:7)

使用迭代器有几个很好的理由,其中一些在这里提到:

以后切换容器不会使代码无效。

即,如果从std :: vector转到std :: list或std :: set,则不能使用数字索引来获取包含的值。使用迭代器仍然有效。

运行时捕获无效迭代

如果在循环中间修改容器,下次使用迭代器时会抛出无效的迭代器异常。

答案 5 :(得分:4)

使用STL,程序员使用iterators遍历容器,因为迭代器是一个抽象概念,在所有标准容器中实现。例如,std::list根本没有operator []

答案 6 :(得分:3)

我很惊讶没有人提到通过使用整数索引迭代数组可以通过使用错误的索引订阅数组来轻松编写错误的代码。例如,如果您使用ij作为索引嵌套循环,则可能会错误地使用j而不是i下标数组,从而将错误引入程序

相比之下,此处列出的其他形式,即基于范围的for循环和迭代器,更不容易出错。语言的语义和编译器的类型检查机制将阻止您使用错误的索引意外访问数组。

答案 7 :(得分:2)

这是一种迭代和打印vector值的简单方法。

for(int x: A) // for integer x in vector A
    cout<< x <<" "; 

答案 8 :(得分:1)

 //different declaration type
    vector<int>v;  
    vector<int>v2(5,30); //size is 5 and fill up with 30
    vector<int>v3={10,20,30};
    
    //From C++11 and onwards
    for(auto itr:v2)
        cout<<"\n"<<itr;
     
     //(pre c++11)   
    for(auto itr=v3.begin(); itr !=v3.end(); itr++)
        cout<<"\n"<<*itr;

答案 9 :(得分:0)

使用auto运算符确实使它易于使用,因为不必担心数据类型和向量的大小或任何其他数据结构

使用auto和for循环迭代向量

vector<int> vec = {1,2,3,4,5}

for(auto itr : vec)
    cout << itr << " ";

输出:

1 2 3 4 5

您还可以使用此方法来迭代集合和列表。使用 auto 会自动检测模板中使用的数据类型,并让您使用它。 因此,即使我们有vectorstring的{​​{1}},也可以使用相同的语法

答案 10 :(得分:0)

迭代循环并打印其值的正确方法如下:

#include<vector>

//declare the vector of type int
vector<int> v;

//insert the 5 element in the vector
for ( unsigned int i = 0; i < 5; i++){
    v.push_back(i);
}

//print those element
for (auto it = 0; it < v.end(); i++){
    std::cout << *it << std::endl;
}

答案 11 :(得分:0)

int main()
{
    int n;
    int input;
    vector<int> p1;
    vector<int> ::iterator it;

    cout << "Enter the number of elements you want to insert" << endl;
    cin >> n;

    for (int i = 0;i < n;i++)
    {
        cin >> input;
        p1.push_back(input);
    }
    for(it=p1.begin();it!=p1.end();it++)
    {
        cout << *it << endl;
    }
      //Iterating in vector through iterator it

    return 0;
}

迭代器的传统形式

答案 12 :(得分:-1)

如果您使用

{
  "reporter": "junit",
  "reporterOptions": {
    "mochaFile": "results/my-test-output.xml",
    "toConsole": true
  }
}

别忘了,当在for循环中使用auto时,也要像下面这样使用get:

std::vector<std::reference_wrapper<std::string>> names{ };