Johannes Schaub 在这里声称
对于您不知道其定义的迭代器,请始终使用前缀增量形式。这将确保您的代码尽可能地通用。
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
/* std::cout << *it; ... */
}
Run Code Online (Sandbox Code Playgroud)
为什么不首先迭代它,然后开始循环(在v.begin()+ 1)?
请注意,您的代码相当于
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ) {
/* std::cout << *it; ... */
++it;
}
Run Code Online (Sandbox Code Playgroud)
很明显,你是否写并不重要++it;或者it++;。(这也解决了你的最后一点。)
但从概念上讲 it++,在其实现中需要存储未递增值的副本,因为这就是表达式的计算结果。
it可能是一个大而重的对象,其获取值副本的计算成本很高,并且您的编译器可能无法优化 . 获取的隐式值副本it++。
如今,对于大多数容器来说,如果不使用表达式的值,编译器将优化可以说更清晰的结果it++;++it即生成的代码将是相同的。
我遵循作者的建议,并且总是尽可能使用预增量,但我(i)守旧,并且(ii)意识到很多专家程序员不这样做,所以这很大程度上取决于个人选择。
为什么不首先迭代它,然后开始循环(在v.begin()+ 1)?
迭代语句始终在每次迭代结束时执行。这与您使用的增量运算符的类型无关,还是根本不使用增量运算符。
不使用迭代语句表达式的结果,因此它对循环的行为没有影响。该声明:
++it;
Run Code Online (Sandbox Code Playgroud)
在功能上等效于以下语句:
it++;
Run Code Online (Sandbox Code Playgroud)
仅当使用表达式的结果时,后缀和前缀增量表达式才具有不同的行为。
为什么对迭代器使用前缀增量形式?
因为后缀操作暗含一个副本。复制迭代器通常至少比不复制迭代器慢,但可能比不复制迭代器慢。
后缀增量的典型实现:
iterator tmp(*this); // copy
++(*this); // prefix increment
return tmp; // return copy of the temporary
// (this copy can be elided by NRVO)
Run Code Online (Sandbox Code Playgroud)
如果不使用结果,则即使第一个副本都可以在线优化,也可以优化掉它。但这并不能保证。
我不会盲目使用“始终在迭代器中使用前缀增量”的规则。用后缀表达一些算法更清晰,尽管这只是我的观点。适用于后缀增量的算法示例:
template<class InIter, class OutIter>
OutIter copy(InIter first, InIter last, OutIter out) {
while(first != last)
*out++ = *first++;
return out;
}
Run Code Online (Sandbox Code Playgroud)