我不熟悉c++语言。我已经开始使用向量,并注意到在我看到的所有通过索引遍历向量的代码中,for循环的第一个参数总是基于向量的值。在Java中,我可以对数组列表做这样的事情:

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

我在c++中看不到这个的原因是什么呢?这是不好的做法吗?


当前回答

不要忘记具有const正确性的例子-循环可以修改元素。这里的许多示例都没有这样做,应该使用cont迭代器。这里我们假设

class T {
  public:
    T (double d) : _d { d } {}
    void doSomething () const { cout << _d << endl; return; }
    void changeSomething ()   { ++_d; return; }
  private:
    double _d;
};

vector<T> v;
// ...
for (const auto iter = v.cbegin(); iter != v.cend(); ++iter) {
    iter->doSomething();
}

还要注意,在c++ 11表示法中,默认是复制元素。使用引用来避免这种情况,和/或允许修改原始元素:

vector<T> v;
// ...
for (auto t : v) {
    t.changeSomething(); // changes local t, but not element of v
    t.doSomething();
}
for (auto& t : v) {      // reference avoids copying element
    t.changeSomething(); // changes element of v
    t.doSomething();
}
for (const auto& t : v) { // reference avoids copying element
    t.doSomething();      // element can not be changed
}

其他回答

使用auto操作符真的很容易使用,因为人们不必担心数据类型和向量或任何其他数据结构的大小

使用auto和for循环迭代vector

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

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

输出:

1 2 3 4 5

您还可以使用此方法迭代集和列表。使用auto会自动检测模板中使用的数据类型,并允许您使用它。 所以,即使我们有一个string或char类型的向量,同样的语法也可以工作得很好

不要忘记具有const正确性的例子-循环可以修改元素。这里的许多示例都没有这样做,应该使用cont迭代器。这里我们假设

class T {
  public:
    T (double d) : _d { d } {}
    void doSomething () const { cout << _d << endl; return; }
    void changeSomething ()   { ++_d; return; }
  private:
    double _d;
};

vector<T> v;
// ...
for (const auto iter = v.cbegin(); iter != v.cend(); ++iter) {
    iter->doSomething();
}

还要注意,在c++ 11表示法中,默认是复制元素。使用引用来避免这种情况,和/或允许修改原始元素:

vector<T> v;
// ...
for (auto t : v) {
    t.changeSomething(); // changes local t, but not element of v
    t.doSomething();
}
for (auto& t : v) {      // reference avoids copying element
    t.changeSomething(); // changes element of v
    t.doSomething();
}
for (const auto& t : v) { // reference avoids copying element
    t.doSomething();      // element can not be changed
}

为什么你没有看到这样的实践是非常主观的,不能有一个明确的答案,因为我已经看到许多代码使用你提到的方式,而不是迭代器风格的代码。

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

每次在循环中都要调用size() 条件。然而,这要么不是问题,要么是小事 固定 优先选择std::for_each()而不是for循环本身 稍后将容器从std::vector更改为其他容器(例如:std::vector)。 Map, list)也会要求改变循环机制, 因为不是每个容器都支持size()类型的循环

c++ 11提供了在容器间移动的良好工具。这被称为“基于范围的for循环”(或Java中的“增强for循环”)。

用很少的代码,你可以遍历完整的(强制的!)std::vector:

vector<int> vi;
...
for(int i : vi) 
  cout << "i = " << i << endl;

遍历vector最简洁的方法是通过迭代器:

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

或(相当于上述)

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

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

This probably is what you have seen. Compared to the approach you mention, the advantage is that you do not heavily depend on the type of vector. If you change vector to a different "collection-type" class, your code will probably still work. You can, however, do something similar in Java as well. There is not much difference conceptually; C++, however, uses templates to implement this (as compared to generics in Java); hence the approach will work for all types for which begin and end functions are defined, even for non-class types such as static arrays. See here: How does the range-based for work for plain arrays?

在vector上迭代并打印其值的正确方法如下:

#include<vector>

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

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

// print those elements
for (auto it = v.begin(); it != v.end(); ++it){
    std::cout << *it << std::endl;
}

但至少在目前的情况下,使用基于范围的for循环会更好: 对于(auto x: v) std::cout << x << "\n"; (你也可以在auto后面加上&,使x成为对元素的引用,而不是它们的副本。它与上面的基于迭代器的方法非常相似,但更易于读写。)