Pages

Sunday, March 7, 2010

Postfix ++. Prefix++

Class Digit in the following program has operator++ implemented in the prefix and postfix forms:
#include <iostream>
using namespace std;

class Digit {
int value;

public:
Digit() : value(0) {}
Digit(const Digit& digit)
{
value = digit.value;
}

//prefix ++
Digit& operator++ ()
{
if (value > 8)
value = 0;
else
value++;
return *this;
}

//postfix ++
Digit operator++(int)
{
Digit digit = *this;
++*this;
return digit;
}

int Value() { return value; }
};

int main (int argc, char * const argv[])
{
Digit digit;
cout << "initially: digit = " << digit.Value() << endl;
digit++;
cout << "postfix ++: digit = " << digit.Value() << endl;
++digit;
cout << "prefix ++: digit = " << digit.Value() << endl;

return 0;
}
The program output is:

[Session started at 2010-03-07 21:38:52 +0200.]
initially:  digit = 0
postfix ++: digit = 1
prefix ++:  digit = 2
The Debugger has exited with status 0.

The following program shows the return values from these operators:
int main (int argc, char * const argv[]) 
{
Digit digit1, digit2;
cout << "initially digit1 = " << digit1.Value() << endl;
cout << " digit2 = " << digit2.Value() << endl;
digit2 = digit1++;
cout << "postfix ++: digit1 = " << digit1.Value() << endl;
cout << " digit2 = " << digit2.Value() << endl;
digit2 = ++digit1;
cout << "prefix ++: digit1 = " << digit1.Value() << endl;
cout << " digit2 = " << digit2.Value() << endl;

return 0;
}

[Session started at 2010-03-08 23:48:15 +0200.]
initially  digit1 = 0
           digit2 = 0
postfix ++: digit1 = 1
            digit2 = 0
prefix ++:  digit1 = 2
            digit2 = 2

The Debugger has exited with status 0.

It behaves exactly as the built-in types:
#include <iostream>

int main (int argc, char * const argv[]) {

int x = 0;
int y = x++;
std::cout << "x = " << x << std::endl;
std::cout << "y = " << y << std::endl;

return 0;
}


run
[Switching to process 813]
Running…
x = 1
y = 0

Debugger stopped.
Program exited with status value:0.


This code (with minor changes) was taken from:
Overloading the increment and decrement operators

The main trick is a fake integer parameter for the postfix operator - it allows to distinguish the postfix and prefix versions. The postfix and prefix operators return different values - the prefix operator return the object after it has been incremented. The postfix operator returns the value before it was incremented.
So it makes sense to prefer prefix operator (preincrement), because it might performs better. The preincrement operator does not have to return the old value that must be stored in a temporary object.

"C++ Std ISO IEC 9899 1990" says about the prefix and postfix operators:

5.2.6 Increment and decrement [expr.post.incr]
1 The value obtained by applying a postfix ++ is the value that the operand had before applying the operator. [Note: the value obtained is a copy of the original value ] The operand shall be a modifiable lvalue. The type of the operand shall be an arithmetic type or a pointer to a complete object type. After the result is noted, the value of the object is modified by adding 1 to it, unless the object is of type bool, in which case it is set to true. [Note: this use is deprecated, see annex D. ] The result is an rvalue. The type of the result is the cv-unqualified version of the type of the operand. See also 5.7 and 5.17.
2 The operand of postfix -- is decremented analogously to the postfix ++ operator, except that the operand shall not be of type bool. [Note: For prefix increment and decrement, see 5.3.2. ]
and below:
5.3.2 Increment and decrement [expr.pre.incr]
1 The operand of prefix ++ is modified by adding 1, or set to true if it is bool (this use is deprecated). The operand shall be a modifiable lvalue. The type of the operand shall be an arithmetic type or a pointer to a completely-defined object type. The value is the new value of the operand; it is an lvalue. If x is not of type bool, the expression ++x is equivalent to x+=1. [Note: see the discussions of addition (5.7) and assignment operators (5.17) for information on conversions. ]
2 The operand of prefix -- is modified by substracting 1. The operand shall not be of type bool. The requirements on the operand of prefix -- and the properties of its result are otherwise the same as those of prefix ++. [Note: For postfix increment and decrement, see 5.2.6. ]
The practical use of the prefix and postfix operator ++ (and maybe the most important) is the input iterators in STL. The following program finds an element in the list:
#include <iostream>
#include <list>

int main (int argc, char * const argv[]) {
int a[10] = { 15, 2, 56, 78, 89, 7, 16, 45, 7, 99 };
std::list<int> myList(&a[0], &a[10]);
std::list<int>::iterator it = std::find(myList.begin(), myList.end(), 7);
if (*it == 7)
std::cout << "7 found in the list" << std::endl;
return 0;
}
Here is the program output:

[Session started at 2010-03-08 23:37:06 +0200.]
7 found in the list

The Debugger has exited with status 0.
And here is a classical istream iterator, which is used to read values from the input stream:
#include <iostream>
#include <iterator>
using namespace std;

int main () {
double value1, value2;
cout << "Please, insert two values: ";

istream_iterator<double> eos; // end-of-stream iterator
istream_iterator<double> iit (cin); // stdin iterator

if (iit!=eos)
value1=*iit;

iit++;
if (iit!=eos)
value2=*iit;

cout << value1 << "*" << value2 << "=" << (value1*value2) << endl;

return 0;
}
Postfix ++ is allows to get the next input value.
For input iterator postfix ++ operation means to step forward and return old position, the prefix ++ also means to step forward and return new position.

No comments:

Post a Comment