为什么使用前缀增量形式的迭代器?

时间:2017-01-20 14:23:36

标签: c++ iterator

Johannes Schaub声称here

  

始终对其定义的迭代器使用前缀增量形式   你不知道。这将确保您的代码像通用一样运行   可能的。

for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
    /* std::cout << *it; ... */
}

为什么不首先迭代它,然后启动循环(在v.begin()+ 1)?

3 个答案:

答案 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。前缀增量意味着增加值,然后返回增加对象的引用;如您所见,在这种情况下根本不使用返回的对象,++itit++将导致相同的结果。