Johannes Schaub声称here
始终对其定义的迭代器使用前缀增量形式 你不知道。这将确保您的代码像通用一样运行 可能的。
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
/* std::cout << *it; ... */
}
为什么不首先迭代它,然后启动循环(在v.begin()+ 1)?
答案 0 :(得分:4)
为什么不首先迭代它,然后启动循环(在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)
当不使用结果时,即使第一个副本也可以被优化掉,但前提是该操作是内联展开的。但这并不能保证。
我不会盲目地使用规则&#34;总是使用前缀增量与itrator&#34;。有些算法用postfix表达更清楚,虽然这只是我的观点。适用于后缀增量的算法示例:
template<class InIter, class OutIter>
OutIter copy(InIter first, InIter last, OutIter out) {
while(first != last)
*out++ = *first++;
return out;
}
答案 1 :(得分:3)
请注意,您的代码等同于
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ) {
/* std::cout << *it; ... */
++it;
}
并且很明显,如果你写++it
并不重要;或it++;
。 (这也解决了你的最后一点。)
但概念上 it++
需要在其实现中存储未增加值的副本,因为这是表达式求值的结果。
it
可能是一个重要的对象,其中获取值副本的计算成本很高,并且您的编译器可能无法优化it++
所采用的隐式值副本。
目前,对于大多数容器,如果未使用表达式的值,编译器将优化可论证的更清晰的it++
到++it
;即生成的代码将是相同的。
我遵循作者的建议,总是尽可能使用预增量,但我(i)老式,(ii)意识到很多专家程序员没有,所以它主要是个人选择。
答案 2 :(得分:1)
为什么不首先迭代它,然后启动循环(在v.begin()+ 1)?
因为for loop将被解析为:
{
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++
将导致相同的结果。