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

jac*_*nad 4 c++ iterator

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)?

Bat*_*eba 5

请注意,您的代码相当于

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)意识到很多专家程序员不这样做,所以这很大程度上取决于个人选择。


eer*_*ika 5

为什么不首先迭代它,然后开始循环(在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)