1

Here is the code snippet:

#include <iostream>
#include <iterator>
#include <algorithm>
#include <functional>
#include <vector>

std::vector<int> vec(5);

int produce_seq()
{
    static int value = 0;
    return (value*value++);
}

int main()
{
    std::generate_n(vec.begin(),5, produce_seq);
    for(auto val:vec)
    {
        std::cout << val <<std::endl;
    }
}

Why this code snippet ouputs

0
2
6
12
20

other than

0
1
4
9
16

I think value*value++; is equivalent to value*value; value++;.

UPDATED:

Should not value++ be evaluated after the entire expression has already been evaluated? For example, if there is a expression like sum=a+b++;, sum=a+b; is always evaluated before b++.

John
  • 2,963
  • 11
  • 33
  • 2
    It's UB, add -Wall to your compiler. And read [this post](https://stackoverflow.com/a/10623165/4123703). – Louis Go Feb 17 '22 at 05:32
  • 2
    With undefined behavior your program may react in any way, even destroying your files. Not just doing the evaluation in the wrong order. – Sebastian Feb 17 '22 at 05:40
  • @Déjàvu Should not value++ be evaluated after the entire expression has already been evaluated? For example, if there is a expression like sum=a+b++;, sum=a+b; is always evaluated before b++. – John Feb 17 '22 at 05:56
  • 1
    It is undefined behaviour. Different compilers generate different results. For example, MSVC 19.29.30037 for x64 on my computer generates the result you assume. Anyway, you can't guarantee that. – Zongru Zhan Feb 17 '22 at 05:57
  • 1
    @John `value` will be incremented after it's been evaluated, as you expect, for *this* `value`, but you use `value` several times, what about the other one? In that case, the behavior you expect is not guaranteed, depending on the compiler implementation. In your case, the result depends on operands evaluation. – Déjà vu Feb 17 '22 at 06:03
  • @Sebastian The magic UB :) People here love those words. Sure, UB might lead to any outcome, as the name implies, and even destroy a satellite in the process. But in this very OP case, the probability of an outcome other than x*(x+1), (x+1)*(x+1) or x*x is pretty low... – Déjà vu Feb 17 '22 at 06:10
  • @Déjàvu It depends on the introspection capabilities of the compiler. Better get used to not producing UB. Also the warnings get better and better. – Sebastian Feb 17 '22 at 10:23

1 Answers1

5

Your program has undefined behavior.

The order in which operands are evaluated is generally unspecified in C++. The only thing we can say in your example is that the value computation of value++ happens before its side effect on value and that the value computations of both the left-hand side and the right-hand side of value*value++ happen before the value computation of value*value++.

This doesn't specify whether the side effect of value++ on value is sequenced before or after the value computation of value on the left-hand side of value*value++. Having a side-effect on a scalar unsequenced with a value computation on the same scalar causes undefined behavior.

Undefined behavior means that you have no guarantee on how the program will behave at all.

For all the details on what kind of evaluations are sequenced, see https://en.cppreference.com/w/cpp/language/eval_order.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • Should not value++ be evaluated after the entire expression has already been evaluated? For example, if there is a expression like sum=a+b++;, sum=a+b; is always evaluated before b++. – John Feb 17 '22 at 05:56
  • 1
    @John No, that is incorrect. It is not specified when the incrementing side-effect of the post-increment operator happens, except that it happens after the result value of `b++` is computed. Usually this detail doesn't matter. For example if `a`, `b` and `sum` are all different objects, then it doesn't matter whether the increment happens inbetween the `+` or `=` or after them. – user17732522 Feb 17 '22 at 05:58
  • 1
    But because this is unspecified you should always avoid using a variable multiple times in an expression if at least one use is modifying it, except for some cases where you can be sure of the sequencing, e.g. if the modification happens only in the form `b = `. – user17732522 Feb 17 '22 at 06:01
  • "***if the modification happens only in the form b =***", what's that? Soryy, I am not native speaker, could you please explain that in simper words or show me a simple example? – John Feb 17 '22 at 06:03
  • 1
    @John `b = b + 1` is ok, although you are using `b` twice and modifying it on the left-hand side. But in such an expression it is guaranteed that the side effect on `b` happens after the value computation on the right-hand side. See rule 8) in the link in my answer. – user17732522 Feb 17 '22 at 06:05