Search

5.4 — Increment/decrement operators, and side effects

Incrementing and decrementing variables

Incrementing (adding 1 to) and decrementing (subtracting 1 from) a variable are so common that they have their own operators.

Operator Symbol Form Operation
Prefix increment (pre-increment) ++ ++x Increment x, then return x
Prefix decrement (pre-decrement) –– ––x Decrement x, then return x
Postfix increment (post-increment) ++ x++ Copy x, then increment x, then return the copy
Postfix decrement (post-decrement) –– x–– Copy x, then decrement x, then return the copy

Note that there are two versions of each operator -- a prefix version (where the operator comes before the operand) and a postfix version (where the operator comes after the operand).

The prefix increment/decrement operators are very straightforward. First, the operand is incremented or decremented, and then expression evaluates to the value of the operand. For example:

This prints:

6 6

The postfix increment/decrement operators are trickier. First, a copy of the operand is made. Then the operand (not the copy) is incremented or decremented. Finally, the copy (not the original) is evaluated. For example:

This prints:

6 5

Let’s examine how this line 6 works in more detail. First, a temporary copy of x is made that starts with the same value as x (5). Then the actual x is incremented from 5 to 6. Then the copy of x (which still has value 5) is returned and assigned to y. Then the temporary copy is discarded.

Consequently, y ends up with the value of 5 (the pre-incremented value), and x ends up with the value 6 (the post-incremented value).

Note that the postfix version takes a lot more steps, and thus may not be as performant as the prefix version.

Here is another example showing the difference between the prefix and postfix versions:

This produces the output:

5 5
6 4
6 4
6 4
7 3

On the 8th line, we do a prefix increment and decrement. On this line, x and y are incremented/decremented before their values are sent to std::cout, so we see their updated values reflected by std::cout.

On the 10th line, we do a postfix increment and decrement. On this line, the copy of x and y (with the pre-incremented and pre-decremented values) are what is sent to std::cout, so we don’t see the increment and decrement reflected here. Those changes don’t show up until the next line, when x and y are evaluated again.

Best practice

Strongly favor the prefix version of the increment and decrement operators, as they are generally more performant, and you’re less likely to run into strange issues with them.

Side effects

A function or expression is said to have a side effect if it does anything that persists beyond the life of the function or expression itself.

Common examples of side effects include changing the value of objects, doing input or output, or updating a graphical user interface (e.g. enabling or disabling a button).

Most of the time, side effects are useful:

The assignment operator in the above example has the side effect of changing the value of x permanently. Even after the statement has finished executing, x will still have the value 5. Similarly with operator++, the value of x is altered even after the statement has finished evaluating. The outputting of x also has the side effect of modifying the state of the console, as you can now see the value of x printed to the console.

However, side effects can also lead to unexpected results:

C++ does not define the order in which function arguments are evaluated. If the left argument is evaluated first, this becomes a call to add(5, 6), which equals 11. If the right argument is evaluated first, this becomes a call to add(6, 6), which equals 12! Note that this is only a problem because one of the arguments to function add() has a side effect.

There are other cases where C++ does not specify the order in which certain things are evaluated (such as operator operands), so different compilers may exhibit different behaviors. Even when C++ does make it clear how things should be evaluated, historically this has been an area where there have been many compiler bugs. These problems can generally all be avoided by ensuring that any variable that has a side-effect applied is used no more than once in a given statement.

Warning

C++ does not define the order of evaluation for function arguments or operator operands.

Best practice

Don’t use a variable that has a side effect applied to it more than once in a given statement. If you do, the result may be undefined.


5.5 -- Comma and conditional operators
Index
5.3 -- Modulus and Exponentiation

180 comments to 5.4 — Increment/decrement operators, and side effects

  • Jon

    So the compiler won't WARN you that it's undefined if you use a variable with side effects applied more than once in a statement?

    It just picks one and goes with it, right? If so, yikes!

  • Benur21

    >" What value does this program print? The answer is: it’s undefined.
    >
    >If the ++ is applied to x before the assignment, the answer will be 1 (postfix operator++ increments x >from 1 to 2, but it evaluates to 1, so the expression becomes x = 1).
    >
    >If the ++ is applied to x after the assignment, the answer will be 2 (this evaluates as x = x, then >postfix operator++ is applied, incrementing x from 1 to 2)."

    Doesn't ++ have a higher precedence level than =? So it is applied first than assignment.

    • Alex

      This is a bit of weirdness in C++ involving a concept called a sequence point. A sequence point is a point where it is guaranteed all side effects have been resolved.

      Here's what we know: postfix ++ will always evaluate before = (based on the rules of precedence). x++ will also always return the value of x as the result of operator++ being evaluated.

      Here's where we get into trouble: The increment of x is considered a side effect. Therefore, we can only say for sure that the increment happens after we hit the next sequence point. You can read about where C++ defines sequence points to be here: https://en.wikipedia.org/wiki/Sequence_point

      Unfortunately (if my understanding is correct) the next sequence point only occurs at the end of the entire statement being evaluated. We can't be assured as to when the increment will occur before then.

  • Benur21

    > "The postfix increment/decrement operators are a little more tricky. The compiler makes a temporary copy of x, increments or decrements the original x (not the copy), and then evaluates the temporary copy of x. The temporary copy of x is then discarded."

    Why doesn't it just first evaluates x, then increments or decrements it? No need for a copy.

  • Martian

    Hi, Alex.
    One of the things I like from your lessons is the rules you establish after the explanations; even if you don't get all the reasoning that leads to it, you still get an unequivocal and practical way to approach code.
    All this said, this is the first time I don't get a rule. I still don't really get what is a side effect (or rather, what isn't one). Up until now I think every line we wrote has a side effect.
    And the wording of the rule makes it even more confusing:
    "Don’t use a variable that has a side effect applied to it more than once in a given statement. If you do, the result may be undefined."
    If by "use" you mean returning or printing or copying the value of said variable, then I can't think of any other thing to do with a variable. And I wonder if it would be maybe better to just state "Don't apply more than one side effect to a variable in the same statement". Otherwise it seems that it's ok to do this if you don't use the variable later (and why would you do that?). Maybe I'm reading it wrong, but I still feel that the sentence is not totally clear.

    Also I wanted to thank you so much for this great course. I'm learning a lot!

    • Alex

      In the context of C++, a side effect is basically any operation that results in modified state for an object (variable) or system (e.g. the output streams).

      Put another way, "A side effect is a result of an operator, expression, statement, or function that persists even after the operator, expression, statement, or function has finished being evaluated." When we talk about applying side effects to variables, we really mean "doing anything that changes the variable's value".

      Notable things that aren't side effects: Temporary values, such as the result of expressions (including evaluating a variable's value, or a function's return value).

      Side effects are generally useful -- almost every expression we write exists to generate a value that we want to do something with -- either store somewhere, or send somewhere (to the console, a file, etc...).

      Saying "Don't apply more than one side effect to a variable in the same statement" isn't quite strict enough, because even taking the value of a variable (which isn't a side effect) in the same statement where a side effect is applied to that variable is dangerous. We see this in the following example:

      There's only one side effect applied to x in this statement, but it's still dangerous because we're not sure when the side effect will be applied.

      Perhaps an alternative wording could be, "if you modify a variable's value in a statement, don't use that variable again in the same statement, otherwise undefined behavior may result".

      Is that clearer? If not, what points of confusion still exist?

      • Martian

        Thank you, Alex! That makes it a lot more clear to me, at least I will know to avoid using variables in that way.
        I partially get your explanation about side effects but it's still a little too abstract to me and I struggle to see it in the actual code. Please correct me if I'm wrong, I know I'm probably simplifying it:
        A side effect is always a value. Not any value, but one that is a result of an operation and is stored in a variable. So if we use that variable in the same statement as the side effect we can't know in which order the values will be evaluated.

        • Alex

          A side effect isn't a value, a side effect is anything that modifies the permanent state of something else. But the remainder is true: if we use a variable with a side effect applied more than once in a statement, we can't be sure when the side effect will be applied in all cases -- so it's better to just avoid this case altogether.

  • Fateh Chadha

    Is there any difference between if and else if?? Because they seem to do the same exact thing!

    • Matthis

      Well from my understanding "else if" will only be executed if your previous "if" statement was false.
      Take a look :

  • prince

    hi Alex
    these are two function used in stack implementation by many sites such as geeksforgeeks
    shouldn't they be used as they contain pre increment(side effects) and assignment operator in same given statement.
    void push(struct Stack* stack, int item)
    {
    if (isFull(stack))
    return;
    stack->array[++stack->top] = item;
    printf("%d pushed to stack\n", item);
    }

    second question
    on codeblocks it evaluates to 13 if x=5 intially.
    x=++x + x++;

    • nascardriver

      Hi prince!

      The push function is not a problem, because you're not assigning a new value to @stack, you're only modifying it's members. Think of it like this

      This obviously isn't problematic.

  • Ujjwal pratap

    #include "stdafx.h"
    #include <iostream>
    int main()
    {
        int x;
        std::cout << "enter :";
        std::cin >> x;
        ++x;                            or when we use x++, then results are same. Why??
        std::cout << x;
        return 0;
    }

    • nascardriver

      Hi Ujjwal!

      The only difference between ++prefix and postfix++ is their return value.
      ++prefix increments and then reads the value to be returned.
      postfix++ reads the value to be returned, then increments, then returns the value which was stored prior to the increment.
      When you're not using the return value of the oparator++, use ++prefix.

  • Nux

    I don't understand this exemple.

    "What value does this program print? The answer is: it’s undefined."

    From the lesson 3.1 (http://www.learncpp.com/cpp-tutorial/31-precedence-and-associativity/)

    I have learn than the Pre-increment operator ++ have an operator precedence of 3 and the operator = an operator precedence of 15

    So this is a define situation. Pre-increment should be resolve first like this: x = (x++);
    and the Incrematation of x should be resolve before the assignement of the x's copy to x

    Or am I missunderstanding something ?

    • Alex

      It seems like it should be as you say (which is why this gets so many C++ programmers into trouble). C++ actually gives the compiler a LOT of leeway in determining the order of evaluation. For example, although you might code a() + b(), either a() or b() could be evaluated first.

      With side effects, this gets a bit weird. We know that x++ both returns the value of x (which happens immediately upon evaluation), and applies a side effect to x that will increment its value. However, the compiler is given a lot of leeway to determine when to schedule the ++ part of the operation. In practice, the ++ could happen before the assignment, or after. If you (or anyone else) want to do more reading, look up the concept of "sequence points" (or sequencing, as of C++11).

  • Nux

    I think the std:: is missing here.

    Here is a version with std:: added

  • Samira Ferdi

    Which is the better or best practices? using x++ or x+=1 for using in a function?

    • nascardriver

      Hi Samira!

      There's no difference. I use ++x unless the 1 is variable and I might change it in the future.

    • Eric

      Hi Samira,

      Logically the two statements are the same (apart from the side affect) but there *could* be a difference in the machine code generated by the compiler.

      The unusual syntax of ++n (or —n) was included in the original C language because the statement would likely result in a single machine code operation often called INC (or DEC) for increment/decrement.  This would presumably perform much better than having to load 2 registers and using an ADD operation.

      But this is highly dependent on the compiler and the CPU instruction set.  And a good compiler/optimizer should be able to reduce n += 1 to an INC instruction anyway.

      Intel x86 CPUs have the INC/DEC instructions but Raspberry Pi computers do not, for example.

      I like to use ++n where it makes sense in case my code is compiled on a CPU that supports the faster increment/decrement operations.

  • Samira Ferdi

    Can we use increment/decrement that adding in real number like adding/subtract 0.1 or 0.001?

    Is there in C++ that implementing other operators in expression like increment/decrement?

    • nascardriver

      Hi Samira!

      The default increment and decrement operators are fixed at 1. Later on you'll learn about defining own data types and own operators which you could use to implement such behavior.

  • Byron

    Hi Alex,
    I wanted to check whether my compiler evaluates the left or right argument first, using the code you provided in this lesson. In theory, one of the two values should have been 11 and the other 12, no? In fact both return 12. Am I understanding things incorrectly here?

    • Alex

      You're seeing unexpected results because you're breaking one of the most broken rules in C++: Don't use a variable with side effects applied more than once in an expression. Operator++ applies a side effect, so you're running afoul of this rule, and the result you're seeing is the result of undefined behavior.

      Here's a program I whipped up that will tell you your evaluation order:

      gen() returns 9 the first time it's called, and 8 the second time. By looking whether left is 8 and right is 9 or vice-versa, we can determine which operand got evaluated first.

      • Byron

        Thanks! And apologies for forcing you to repeat the same thing again.
        I thought I was not using it twice in an argument actually as I was using the operator only once. I guess it's the variable that I should count and not how many times I am using the operator.

      • Rohit

        Hi Alex.

        I'm failing to understand your program. The way I see it, the function "gen()" is called two times with its own local scope each time, so it would return 9 every time. Getting called once wouldn't have any effect on any subsequent calls. This is especially true considering "x" is a static integer.

        Well that's what I had initially thought, anyway. What am I understanding incorrectly? How do the 2 calls to gen() provide different results?

        • nascardriver

          Hi Rohit!

          @x is in the scope of @get, but @x's lifetime begins with the first call to @gen and ends with the program's exit, not with the end of @gen. You can treat @x as a global variable with limited scope.

          References
          Lesson 4.3 — Static duration variables

          • Rohit

            I see, thanks!

            So it's because of the static variable, which comes in the future. I was thinking "static" was another way of having a constant variable but that's where the English language messed me up, haha.

  • Michael

    Hi Alex,
    The post increment operator has a higher precedence than assignment operator. Doesn't it mean that

    will be executed in the same way as

    which has a defined behavior?

    • Alex

      No. The higher precedence means x++ is evaluated first. That evaluation means x++ will be evaluated to produce the value x. The actual increment part is not guaranteed to happen immediately (think of post-increment as "increment at some point in the future"). So it could be the assignment happens first, or the ++ happens first.

      This was probably originally done for performance reasons, but is one of those annoying quirks of the language that you have to learn not to do.

  • Aditya

    So, is it best if we don't use the increment/decrement operators at all?

    • Alex

      You should feel free to use the increment and decrement operators. Just don't use the variables you're using those operators on more than once in a given statement.

  • The Perplexed Programmer

    Reminds me of a joke.

    "Hey, how to increment a variable C?"
    "C++..."

  • Lim Che Ling

    Hi, Alex,

    I am very confused about prefix and postfix ++ and the explanation term "evaluates and increment" as well as the rvalue and lvalue in this context.

    int x = 5;
    int y = x++;  //postfix ++ will Evaluate x, then increment x

    In this e.g., I understand in this way "First, a memory location x with value 5 is made a temporary copy with temp copy which has value 5. Then 'Evaluate x' means 'assign value of temp copy 5 to y', discard temp copy, incrementing x from 5 to 6."

    So with same token,

    int x = 5;
    ++x++; //This evaluates to ++(x++) due to postfix has higher precedence than prefix
    So on the postfix x++, it will Evaluate x, then increment x.

    In this case, "First, a memory location x with value 5 is made a temporary copy with temp copy which has value 5(now has two memory locations with value 5). Then 'Evaluate x' means 'working on ++x' which would evaluate to temporary copy increased to 6 then discard temporary copy, then incrementing original x from 5 to 6.

    Somehow, my understanding lacks of incorporation of r-value and l-value concept inside and so it seems compiler should compile though I think something is amiss.

    • Alex

      Don't worry about r-values and l-values in this context. int x = 5 is just memory location x being initialized with value 5. x++ evaluates to 5 means that the compiler reduces that expression to the singular value 5. So even though x is incremented to 6 (as a side effect), the value 5 is assigned to y, since that's what x++ evaluated to.

  • P8yan

    "If the ++ is applied to x before the assignment, the answer will be 1 (prefix operator++ increments x from 1 to 2, but it evaluates to 1, so the expression becomes x = 1)."

    I believe "prefix" above was meant to be "postfix".

  • Stephane

    Hi Alex, What do you mean by te outputting of x modifying the console?
    Great tutorial, thanks

    • Alex

      Outputting the value x to the console changes the state of the console such that it now displays the value of x, whereas before it did not.

  • Hi Alex. Can you please explain this program. This is the same program given in example in this chapter but I made a change in the line where the add function is called. I added pre-decrement operator. When I executed your example without any change, the output was 12, which means that my compiler (code blocks) first operates on the right argument. If it is so, then this program should have given 11 as output but the output given is 10.

    Thanks in advance

    • Alex

      Rule: Don't use a variable that has a side effect applied to it more than once in a given statement. If you do, the result is undefined.

  • John

    Hi! Great tutorials!
    I have a bit of a question...
    I wrote a code that finds the prime numbers up to 100. It works fine, but I can't figure it out how to deal with the first prime number, witch is 2.
    I put there a separate if statement, just to output 2, and after that it goes normal for the rest of the numbers.
    But I would like to make the code more generic, without working separately just for 2.

    Here's the code:

    If I exclude this part:

    the code outputs prime numbers starting from 3...
    I have tried to change the initial values of dividend and divisor but without any success.

    • Alex

      I'd probably just move this part:

      inside the while loop. That way your while loop logic will work for the number 2. I can't think of a way to not special-case it.

    • Liam

      I edited your code slightly (and used it as a means of practice) to give the user the ability to set their own limit.

  • MJ

    Great content, as always.

    Minor clarification point: Since x++ evaluates first, then assigns, I think this line in your second example should be changed from:

    to

    This would help the reader and is (I think) more in line with the definition provided.

  • Pritam Das

    #include<iostream>
    void main()
    {

       int x =5, y;
       y =x++ + ++x;
       cout<<++y<<" "<<y++;
    }
    the output is
    14 12

    dear alex ,plz tell me the logic behind the output,

    • Alex

      Rule: Don't use a variable that has a side effect applied to it more than once in a given statement. If you do, the result is undefined.

  • John

    "C++ does not define the order in which function arguments are evaluated."

    In the example below, does this mean that it is not guaranteed that line 11, i.e. array[x++], will be evaluated to 10 for every compiler?

    x = 1
    10
    x = 2

    Is it correct wording to say that array[x++] evaluates to 10 in this example?

    • Alex

      Your program doesn't call any functions with multiple arguments, so the order of evaluation issue isn't applicable here.

      array[x++] will always evaluate to 10 here.

      • John

        So, looking at line 11 i the code above, i.e.

        From the Table in section 3.1 we find the precedence and the associativity for the post-increment (x++) and the array subscript operators [], respectively

        2 L->R    ++    Post-increment    (x++)
        2 L->R    []    Array subscript

        They have the same precedence level 2, and the same associativity L->R. How is the rule applied now? It's not evaluated L->R, more from inside and out, how does the compiler read the code array[x++] (what rules are applied)?

        Just a note, the pre-increment operator (++x) has a lower order of precedence, and associative R->L, i.e.

        3 R->L    ++    Pre-increment    (++x)

        Replacing line 11 in the code with

        20

        • Alex

          In the post-increment case, the subscript operator is evaluated first (because it's to the left of the postfix-++), and a function named operator[] is called with x++ as a parameter. At this point, x++ gets evaluated to the value of x, which is passed into operator[], which uses that value to subscript the array.

          It works the same way in the pre-increment case, except ++x evaluates to x+1, which is the value that gets passed into the subscript function and used to subscript the array.

  • Bernat

    I don't see the problem in the last one, I mean, if ++ is evaluated first then x will be 2 and then the = will be evaluated which will make x be 2. If the = is evaluated first x = x which is one, and then the ++ will be evaluated which will cause x to be 2, right? I guess I'm doing it wrong in some part, but I don't know how.

    • Alex

      I've updated the lesson with a little more detail about how these expressions evaluate. Have a re-read and let me know if you have additional questions.

      • Vlad

        I think I might know the cause of his confusion cause as I've scratched my head for a few seconds as well.

        "If the ++ is applied to x before the assignment, the answer will be 1 (postfix operator++ increments x from 1 to 2, but it evaluates to 1, so the expression becomes x = 1).

        If the ++ is applied to x after the assignment, the answer will be 2 (this evaluates as x = x, then postfix operator++ is applied, incrementing x from 1 to 2)."

        In the first paragraph, I think it should be prefix operator instead of postfix. Thanks for the awesome tutorials!

  • Arsala

    #include <iostream>

    using namespace std;

    int main()
    {
        int a=5;
        cout<<a++<<" "<<a++<<" "<<++a<<" "<<a++<<" "<<++a<<endl;
        return 0;
    }

    I have problem with this code , I am not understanding the output result that is 9 8 10 6 10 rather according to me it should 5 6 8 8 10
    please reply

  • Andreas

    question 1:

    question 2:

    question 3:

    right?

  • int main()
    {
        int x = 1;
        x = x++;
        std::cout << x;

        return 0;
    }

    What value does this program print? The answer is: it’s undefined. If the ++ is applied to x before the assignment, the answer will be 1. If the ++ is applied to x after the assignment, the answer will be 2.

    Could you explain this to me more????

    • Alex

      Unfortunately, the answer is somewhat complicated, and has to do with something called sequence points. A sequence point is a point in the program where it's guaranteed that all side effects from previous evaluations have been performed. Between sequence points, the order of side effects resolution is indeterminate.

      The challenge with this particular program is that the side effects from postfix operator++ and the assignment operator aren't separated by a sequence point, so the compiler is free to apply those side effects in either order.

      If the ++ is applied after the assignment: First x++ evaluates to 1. That 1 is assigned to x. Then the ++ is applied to x, which increments it to 2.
      If the ++ is applied to x before the assignment: First x++ evaluates to 1. The ++ is then applied, changing the value of x to 2. The value of 1 from the previous evaluation is then assigned to x, leaving x with the final value of 1.

      Both of these are valid interpretations of how to resolve the expression in C++, and different compilers may choose to do it differently.

  • Max Payne

    Hello Alex !
    I have a problem !
    #include <iostream>

    int main()
    {
        int x = 10;
        int z = (++x) + (x++);
        std::cout << z;
        return 0;
    }

    Why This code is producing the result 23 ?
    I think it should produce the result 22....
    PLEASE HELP ME !!

    • Alex

      When you use a variable with a side effect applied more than in a single statement, the result is undefined.

      On your compiler, it produces 23. On another compiler, it may produce 22. On a third compiler, it may produce something else.

  • saratha

    Hi

    int ch=20;
    cout<<ch<<++ch<<ch<<"\n";

    output I got was 21 21 20.somewhere I read calculations takes place from right to left.Printing takes place from left to right.kindly explain

Leave a Comment

Put all code inside code tags: [code]your code here[/code]