前缀或后缀自增(或自减)的使用

Usage of prefix or postfix increment (or decrement)

本文关键字:后缀 前缀      更新时间:2023-10-16

我发现这段代码是c++书籍(c++ Primer, 5th Edition)中逗号操作符使用的一个例子:

vector<int>::size_type cnt = ivec.size();
// assign values from size...1 to the elements in ivec
for(vector<int>::size_type ix = 0; ix != ivec.size(); ++ix, --cnt)
    ivec[ix] = cnt;

我认为这不是一个合适的例子,因为计算的顺序和副作用在这里并不重要。逗号操作符只允许分隔自增和自减表达式,这是逗号操作符的常用用法,但不是本书本节的目的。cppreference.com显示了一个更好的例子(请向下滚动到标题内置逗号操作符)。

我真正想到的是下面的练习:

本节中的程序使用了前缀自增和自减操作符。解释为什么我们使用前缀而不是后缀。要使用后缀必须做哪些更改版本?使用后置操作符重写程序。

在这种情况下,没有特别的理由选择前缀操作符而不是后缀操作符。求值顺序并不重要。对simple类型的对象(如vector<int>::size_type)的操作在实践中不应该从使用前缀而不是后缀中受益,因此为了性能问题,使用前缀而不是后缀只是一种已知的惯例。

为了给你完整的背景,这里是书中的部分:

4.10逗号算子
逗号操作符接受两个操作数,从左到右求值。就像逻辑上的AND AND逻辑和条件运算符,逗号运算符保证其操作数的求值顺序。

左边的表达式被求值,其结果被丢弃。逗号表达式的结果是其右侧的值表达式。如果右操作数为an,则结果为左值左值。逗号操作符的一种常见用法是在for循环中:

vector<int>::size_type cnt = ivec.size();  
// assign values from size...1 to the elements in ivec  
for(vector<int>::size_type ix = 0; ix != ivec.size(); ++ix, --cnt)  
    ivec[ix] = cnt;  

该循环对表达式in中的ix递增,对cnt递减for标头。ixcnt在每次穿越时都要更改循环。只要ix的测试成功,我们就重置下一个当前元素到的当前值。

我说的对吗?还是我不明白这个练习的目的?

你是对的,在这个例子中使用前缀或后缀递增运算符并不重要,但是 c++ Primer也说只有在真正必要的时候才使用后缀版本作为最佳实践,我引用了§4.5的书。自增和自减运算符

建议:仅在必要时使用后缀操作符

具有C背景的读者可能会对我们在编写的程序中使用前缀自增感到惊讶。原因很简单:前缀版本避免了不必要的工作。它将值递增并返回递增的版本。后缀操作符必须存储原始值,以便返回未加1的值作为结果。如果不需要未加1的值,则不需要后缀操作符所做的额外工作。

对于int和指针,编译器可以优化掉这些额外的工作。对于更复杂的迭代器类型,这些额外的工作可能会更昂贵。通过习惯性地使用前缀版本,我们不必担心性能差异是否重要。而且,也许更重要的是,我们可以更直接地表达程序的意图。