Team LiB
Previous Section Next Section

5.5. Increment and Decrement Operators

5.5. 自增和自减操作符

The increment (++) and decrement (--) operators provide a convenient notational shorthand for adding or subtracting 1 from an object. There are two forms of these operators: prefix and postfix. So far, we have used only the prefix increment, which increments its operand and yields the changed value as its result. The prefix decrement operates similarly, except that it decrements its operand. The postfix versions of these operators increment (or decrement) the operand but yield a copy of the original, unchanged value as its result:

自增(++)和自减(--)操作符为对象加1或减1操作提供了方便简短的实现方式。它们有前置和后置两种使用形式。到目前为止,我们已经使用过前自增操作,该操作使其操作数加1,操作结果是修改后的值。同理,前自减操作使其操作数减 1。这两种操作符的后置形式同样对其操作数加 1(或减 1),但操作后产生操作数原来的、未修改的值作为表达式的结果:

     int i = 0, j;
     j = ++i; // j = 1, i = 1: prefix yields incremented value
     j = i++; // j = 1, i = 2: postfix yields unincremented value

Because the prefix version returns the incremented value, it returns the object itself as an lvalue. The postfix versions return an rvalue.

因为前置操作返回加1后的值,所以返回对象本身,这是左值。而后置操作返回的则是右值。

Advice: Use Postfix Operators Only When Necessary

建议:只有在必要时才使用后置操作符

Readers from a C background might be surprised that we use the prefix increment in the programs we've written. The reason is simple: The prefix version does less work. It increments the value and returns the incremented version. The postfix operator must store the original value so that it can return the unincremented value as its result. For ints and pointers, the compiler can optimize away this extra work. For more complex iterator types, this extra work potentially could be more costly. By habitually favoring the use of the prefix versions, we do not have to worry if the performance difference matters.

有使用 C 语言背景的读者可能会觉得奇怪,为什么要在程序中使用前自增操作。道理很简单:因为前置操作需要做的工作更少,只需加 1 后返回加 1 后的结果即可。而后置操作符则必须先保存操作数原来的值,以便返回未加 1 之前的值作为操作的结果。对于 int 型对象和指针,编译器可优化掉这项额外工作。但是对于更多的复杂迭代器类型,这种额外工作可能会花费更大的代价。因此,养成使用前置操作这个好习惯,就不必操心性能差异的问题。


Postfix Operators Return the Unincremented Value

后置操作符返回未加1的值

The postfix version of ++ and -- is used most often when we want to use the current value of a variable and increment it in a single compound expression:

当我们希望在单个复合表达式中使用变量的当前值,然后再加1时,通常会使用后置的 ++-- 操作:

     vector<int> ivec;           // empty vector
     int cnt = 10;
     // add elements 10...1 to ivec
     while (cnt > 0)
         ivec.push_back(cnt--);  // int postfix decrement

This program uses the postfix version of -- to decrement cnt. We want to assign the value of cnt to the next element in the vector and then decrement cnt before the next iteration. Had the loop used the prefix version, then the decremented value of cnt would be used when creating the elements in ivec and the effect would be to add elements from 9 down to 0.

这段程序使用了后置的 -- 操作实现 cnt 减 1。我们希望把 cnt 的值赋给 vector 对象的下一个元素,然后在下次迭代前 cnt 的值减 1。如果在循环中使用前置操作,则是用 cnt 减 1 后的值创建 ivec 的新元素,结果是将 90 十个元素依次添加到 ivec 中。

Combining Dereference and Increment in a Single Expression

在单个表达式中组合使用解引用和自增操作

The following program, which prints the contents of ivec, represents a very common C++ programming pattern:

下面的程序使用了一种非常通用的 C++ 编程模式输出 ivec 的内容:

     vector<int>::iterator iter = ivec.begin();
     // prints 10 9 8 ... 1
     while (iter != ivec.end())
         cout << *iter++ << endl; // iterator postfix increment

The expression *iter++ is usually very confusing to programmers new to both C++ and C.

如果程序员对 C++ 和 C 语言都不太熟悉,则常常会弄不清楚表达式 *iter++ 的含义。

The precedence of postfix increment is higher than that of the dereference operator, so *iter++ is equivalent to *(iter++). The subexpression iter++ increments iter and yields a copy of the previous value of iter as its result. Accordingly, the operand of * is a copy of the unincremented value of iter.

由于后自增操作的优先级高于解引用操作,因此 *iter++ 等效于 *(iter++)。子表达式 iter++ 使 iter 加 1,然后返回 iter 原值的副本作为该表达式的结果。因此,解引用操作 * 的操作数是 iter 未加 1 前的副本。

This usage relies on the fact that postfix increment returns a copy of its original, unincremented operand. If it returned the incremented value, we'd dereference the incremented value, with disastrous results: The first element of ivec would not get written. Worse, we'd attempt to dereference one too many elements!

这种用法的根据在于后自增操作返回其操作数原值(没有加 1)的副本。如果返回的是加 1 后的值,则解引用该值将导致错误的结果:ivec 的第一个元素没有输出,并企图对一个多余的元素进行解引用。

Advice: Brevity Can Be a Virtue

建议:简洁即是美

Programmers new to C++ who have not previously programmed in a C-based language often have trouble with the terseness of some expressions. In particular, expressions such as *iter++ can be bewilderingat first. Experienced C++ programmers value being concise. They are much more likely to write

没有 C 语言基础的 C++ 新手,时常会因精简的表达式而苦恼,特别是像 *iter++ 这类令人困惑的表达式。有经验的 C++程序员非常重视简练,他们更喜欢这么写:

     cout << *iter++ << endl;

than the more verbose equivalent

而不采用下面这种冗长的等效代码:

     cout << *iter << endl;
     ++iter;

For programmers new to C++, the second form is clearer because the action of incrementing the iterator and fetching the value to print are kept separate. However, the first version is much more natural to most C++ programmers.

对于初学 C++ 的程序员来说,第二种形式更清晰,因为给迭代器加 1 和获取输出值这两个操作是分开来实现的。但是更多的 C++ 程序员更习惯使用第一种形式。

It is worthwhile to study examples of such code until their meanings are immediately clear. Most C++ programs use succinct expressions rather than more verbose equivalents. Therefore, C++ programmers must be comfortable with such usages. Moreover, once these expressions are familiar, you will find them less error-prone.

要不断地研究类似的代码,最后达到一目了然的地步。大部分的 C++ 程序员更喜欢使用简洁的表达式而非冗长的等效表达式。因此,C++ 程序员必须熟悉这种用法。而且,一旦熟悉了这类表达式,我们会发现使用起来更不容易出错。

Exercises Section 5.5

Exercise 5.15:

Explain the difference between prefix and postfix increment.

解释前自增操作和后自增操作的差别。

Exercise 5.16:

Why do you think C++ wasn't named ++C?

你认为为什么C++不叫做++C?

Exercise 5.17:

What would happen if the while loop that prints the contents of a vector used the prefix increment operator?

如果输出vector内容的while循环使用前自增操作符,那会怎么样?


Team LiB
Previous Section Next Section