C++11 documentation has dropped the term “sequence point” because the concept doesn’t carry over well when discussing multiple threads of execution. Instead, descriptions are framed in terms of sequencing, with some events being described as being sequenced before other events. This descriptive approach isn’t intended to change the rules; the goal is to provide language that can more clearly handle multithreaded programming.
Prefixing Versus Postfixing
Clearly, whether you use the prefix or postfix form makes a difference if the value is used for some purpose, such as a function argument or assigning to a variable. But what if the value of an increment or decrement expression isn’t used? For example, are
x++;
and
++x;
different from one another? Or are
for (n = lim; n > 0; --n)
...;
and
for (n = lim; n > 0; n--)
...;
different from one another?
Logically, whether the prefix or postfix forms are used makes no difference in these two situations. The values of the expressions aren’t used, so the only effects are the side effects. Here the expressions using the operators are full expressions, so the side effects of incrementing x and decrementing n are guaranteed to be performed by the time the program moves on to the next step; the prefix form and postfix form lead to the same final result.
However, although the choice between prefix and postfix forms has no effect on the program’s behavior, it is possible for the choice to have a small effect on execution speed. For built-in types and modern compilers, this seems to be a non issue. But C++ lets you define these operators for classes. In that case, the user defines a prefix function that works by incrementing a value and then returning it. But the postfix version works by first stashing a copy of the value, incrementing the value, and then returning the stashed copy. Thus, for classes, the prefix version is a bit more efficient than the postfix version.
In short, for built-in types, it most likely makes no difference which form you use. For user-defined types having user-defined increment and decrement operators, the prefix form is more efficient.
The Increment/Decrement Operators and Pointers
You can use increment operators with pointers as well as with basic variables. Recall that adding an increment operator to a pointer increases its value by the number of bytes in the type it points to. The same rule holds for incrementing and decrementing pointers:
double arr[5] = {21.1, 32.8, 23.4, 45.2, 37.4};
double *pt = arr; // pt points to arr[0], i.e. to 21.1
++pt; // pt points to arr[1], i.e. to 32.8
You can also use these operators to change the quantity a pointer points to by using them in conjunction with the * operator. Applying both * and ++ to a pointer raises the questions of what gets dereferenced and what gets incremented. Those actions are determined by the placement and precedence of the operators. The prefix increment, prefix decrement, and dereferencing operators all have the same precedence and associate from right to left. The postfix increment and decrement operators both have the same precedence, which is higher than the prefix precedence. These two operators associate from left to right.
The right-to-left association rule for prefix operators implies that *++pt means first apply ++ to pt (because the ++ is to the right of the *) and then apply * to the new value of pt:
double x = *++pt; // increment pointer, take the value; i.e., arr[2], or 23.4
On the other hand, ++*pt means obtain the value that pt points to and then increment that value:
++*pt; // increment the pointed to value; i.e., change 23.4 to 24.4
Here, pt remains pointing to arr[2].
Next, consider this combination:
(*pt)++; // increment pointed-to value
The parentheses indicate that first the pointer is dereferenced, yielding 24.4. Then the ++ operator increments that value to 25.4; pt remains pointing at arr[2].
Finally, consider this combination:
x = *pt++; // dereference original location, then increment pointer
The higher precedence of the postfix ++ operator means the ++ operator operates on pt, not on *pt, so the pointer is incremented. But the fact that the postfix operator is used means that the address that gets dereferenced is the original address, &arr[2], not the new address. Thus, the value of *pt++ is arr[2], or 25.4, but the value of pt after the statement completes is the address of arr[3].
Note
Incrementing and decrementing pointers follow pointer arithmetic rules. Thus, if pt points to the first member of an array, ++pt changes pt so that it points to the second member.
Combination Assignment Operators
Listing 5.5 uses the following expression to update a loop counter:
i = i + by
C++ has a combined addition and assignment operator that accomplishes the same result more concisely:
i += by