Johannes Schaub声称这里
对于那些定义未知的迭代器,始终使用前缀递增形式。这将确保您的代码尽可能地通用。
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
/* std::cout << *it; ... */
}
为什么不先迭代第一个元素,然后从v.begin() + 1开始循环?
为什么不先迭代第一个元素,然后从v.begin() + 1开始循环?
迭代语句总是在每次迭代结束时执行。这与你使用的递增运算符的类型无关,或者你是否使用递增运算符。
迭代语句表达式的结果不会被使用,因此它对循环行为没有影响。以下语句:
++it;
功能等同于该语句:
it++;
后缀和前缀递增表达式只有在使用表达式结果时才有不同的行为。
为什么要对迭代器使用前缀递增形式?
因为后缀操作意味着复制。复制一个迭代器通常至少与不复制一个迭代器一样慢,但潜在地更慢。
后缀递增的典型实现:
iterator tmp(*this); // copy
++(*this); // prefix increment
return tmp; // return copy of the temporary
// (this copy can be elided by NRVO)
如果结果没有被使用,即使第一次复制也可以进行优化,但只有当操作在内联扩展时才能保证。
我不会盲目地使用“始终使用迭代器前缀增量”的规则。有些算法用后缀更清晰,尽管这只是我的意见。适合使用后缀增量的算法示例:
template<class InIter, class OutIter>
OutIter copy(InIter first, InIter last, OutIter out) {
while(first != last)
*out++ = *first++;
return out;
}
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ) {
/* std::cout << *it; ... */
++it;
}
++it;
或者it++;
都没关系。(这也回答了你的最后一个问题。)it++
在其实现中需要存储未递增值的副本,因为这就是表达式的求值结果。
it
可能是一个大而笨重的对象,复制它的值会消耗计算资源,而且你的编译器可能无法优化it++
隐含的值复制。it++
优化为++it
;也就是说,生成的代码将是相同的。为什么不先迭代第一个,然后从v.begin() + 1开始循环?
{
init_statement
while ( condition ) {
statement
iteration_expression ;
}
}
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
/* std::cout << *it; ... */
}
等同于
{
std::vector<T>::iterator it = v.begin();
while ( it != v.end() ) {
/* std::cout << *it; ... */
++it ;
}
}
v.begin()
处执行循环,然后向前移动it
。前缀递增意味着增加值,然后返回增加对象的引用;由于在此情况下未使用返回的对象,则++it
和it++
将导致相同的结果。