这总是取决于你需要什么。

当您使用 需要直接访问向量中的元素时(当您需要索引向量中的特定元素时) ,应该使用 operator[]。在迭代器上使用它没有错。但是,您必须自己决定哪个(operator[]或迭代器)最适合您的需要。

使用迭代器将使您能够切换到其他容器类型,而不需要对代码进行太多更改。换句话说,使用迭代器将使代码更加通用,并且不依赖于特定类型的容器。

这是一个速度的问题。使用迭代器访问元素更快。这里回答了一个类似的问题:

什么更快,迭代一个 STL 向量与向量: : 迭代器或与() ?

编辑: 访问速度因 CPU 和编译器而异

迭代器的好处是,稍后如果您想将向量切换到另一个 STD 容器,可以使用它。那么 forloop 仍然可以工作。

迭代器使代码更加通用。
每个标准库容器都提供了一个迭代器,因此,如果将来更改容器类,循环不会受到影响。

迭代器是 operator[]的首选,C + + 11提供 std::begin()std::end()函数。

由于您的代码只使用 std::vector,我不能说两个代码有很大的差异,但是,operator []可能不会按照您的意图操作。例如,如果使用 map,如果找不到,operator[]将插入一个元素。

此外,通过使用 iterator,您的代码在容器之间变得更加可移植。如果使用迭代器,您可以自由地将容器从 std::vector切换到 std::list或其他容器,而不需要做太多更改,这样的规则不适用于 operator[]

使用向量迭代器不会提供任何真正的优势。语法更难看,输入时间更长,也更难读。

使用迭代器对向量进行迭代不会更快,也不会更安全(实际上,如果在迭代过程中使用迭代器可能调整向量的大小,将会给您带来很大的麻烦)。

在实际情况中,当您稍后更改容器类型时,拥有一个可以工作的通用循环的想法也基本上是无意义的。不幸的是,严格类型语言没有严格的类型推断(不过现在 C + + 11更好一些)的黑暗面是,您需要在每个步骤中说出所有东西的类型。如果你以后改变了主意,你仍然需要四处走走,改变一切。此外,不同的容器有非常不同的权衡和改变容器类型不是经常发生的事情。

在编写模板代码时,如果可能的话,应该保持泛型迭代的唯一情况是,但是(我希望您)并不是最常见的情况。

显式索引循环中存在的唯一问题是 size返回一个无符号值(C + + 的一个设计错误) ,在有符号和无符号之间进行比较是危险和令人惊讶的,因此最好避免。如果您使用启用了警告的体面的编译器,那么应该对其进行诊断。

注意,解决方案不是使用无符号索引,因为无符号值之间的算术显然也是不合逻辑的(这是模算术,而且 x-1可能大于 x)。相反,您应该在使用它之前将大小强制转换为整数。 只有在使用16位 C + + 实现(16位是大小中包含无符号值的原因)时,使用无符号大小和索引(对所编写的每个表达式都要多加注意)才有意义。

作为未签名大小可能引入的一个典型错误,请考虑:

void drawPolyline(const std::vector<P2d>& points)
{
for (int i=0; i<points.size()-1; i++)
drawLine(points[i], points[i+1]);
}

这里存在一个 bug,因为如果传递一个空的 points向量,值 points.size()-1将是一个巨大的正数,使您进入一个 Segfault 循环。 一个可行的解决方案是

for (int i=1; i<points.size(); i++)
drawLine(points[i - 1], points[i]);

但是我个人更喜欢用 int(v.size())去除 unsinged-ness。

PS: 如果你真的不想自己去思考这个问题的含义,只是想让一个专家告诉你,那么考虑一下相当多的世界公认的 C + + 专家同意并表达了他们对 除了位操作之外,无符号值不是一个好主意的看法。

在迭代到倒数第二的情况下发现使用迭代器的丑陋是留给读者的练习。

迭代器的特殊之处在于它们提供了 算法和容器之间的粘合剂。对于通用代码,建议使用 STL 算法(例如 findsortremovecopy)等的组合,这些算法执行你想到的数据结构计算(vectorlistmap等) ,并将迭代器提供给你的容器。

您的特定示例可以编写为 for_each算法和 vector容器的组合(参见下面的选项3) ,但是只有四种不同的方法可以在 std: : Vector 上迭代:

1)基于索引的迭代

for (std::size_t i = 0; i != v.size(); ++i) {
// access element as v[i]


// any code including continue, break, return
}

优点 : 熟悉 C 风格代码的人都很熟悉,可以使用不同的步骤(例如 i += 2)进行循环。

缺点 : 只适用于顺序随机存取容器(vectorarraydeque) ,不适用于 listforward_list或关联容器。此外,循环控制有点冗长(init、 check、  增量)。人们需要注意 C + + 中基于0的索引。

2)基于迭代器的迭代

for (auto it = v.begin(); it != v.end(); ++it) {
// if the current index is needed:
auto i = std::distance(v.begin(), it);


// access element as *it


// any code including continue, break, return
}

优点 : 更通用,适用于所有容器(即使是新的无序关联容器,也可以使用不同的步长(如 std::advance(it, 2)) ;

缺点 : 需要额外的工作来获取当前元素的索引(list 或 forward _ list 可以是 O (N))。同样,循环控制有点冗长(init、 check、  增量)。

3) STL for _ each 算法 + lambda

std::for_each(v.begin(), v.end(), [](T const& elem) {
// if the current index is needed:
auto i = &elem - &v[0];


// cannot continue, break or return out of the loop
});

优点 : 与2相同)加上循环控制的小减少(无检查和增量) ,这可以大大降低错误率(错误初始化、检查或增量、错误一次性)。

缺点 : 与显式迭代器循环相同,循环中流控制的可能性受到限制(不能使用继续、中断或返回) ,不能选择不同的步长(除非使用重载 operator++的迭代器适配器)。

4)循环范围

for (auto& elem: v) {
// if the current index is needed:
auto i = &elem - &v[0];


// any code including continue, break, return
}

优点 : 非常紧凑的循环控制,直接访问当前元素。

缺点 : 额外的语句来获取索引。不能使用不同的步长。

使用什么

对于在 std::vector上迭代的特殊例子: 如果你真的需要索引(例如访问前一个或下一个元素,打印/记录循环中的索引等) ,或者你需要一个不同于1的步长,那么我会选择显式索引循环,否则我会选择 range-For 循环。

对于通用容器上的通用算法,我会选择显式迭代器循环,除非代码在循环中不包含流控制,并且需要跨越1,在这种情况下,我会选择 STL for_each + a lambda。

通过使用迭代器编写客户机代码,可以完全抽象出容器。

考虑下面的代码:

class ExpressionParser // some generic arbitrary expression parser
{
public:
template<typename It>
void parse(It begin, const It end)
{
using namespace std;
using namespace std::placeholders;
for_each(begin, end,
bind(&ExpressionParser::process_next, this, _1);
}
// process next char in a stream (defined elsewhere)
void process_next(char c);
};

客户端代码:

ExpressionParser p;


std::string expression("SUM(A) FOR A in [1, 2, 3, 4]");
p.parse(expression.begin(), expression.end());


std::istringstream file("expression.txt");
p.parse(std::istringstream<char>(file), std::istringstream<char>());


char expr[] = "[12a^2 + 13a - 5] with a=108";
p.parse(std::begin(expr), std::end(expr));

编辑: 考虑您的原始代码示例,使用以下方法实现:

using namespace std;


vector<int> myIntVector;
// Add some elements to myIntVector
myIntVector.push_back(1);
myIntVector.push_back(4);
myIntVector.push_back(8);


copy(myIntVector.begin(), myIntVector.end(),
std::ostream_iterator<int>(cout, " "));