2

Can someone shed some light in what could be happening in these cases (by either using Case 1 or Case 2) and why it gives different results:

Case 1:

currentIndex = 1                                                                                                                                                                                              
vec = {1, 0, 0}

Case 2:

currentIndex = 1                                                                                                                                                                                              
vec = {0, 1, 0}

Code:

#include <iostream>
#include <vector>

using namespace std;

uint currentIndex = 0;

uint testFunc()
{
    currentIndex++;
    return 1;
}

int main()
{
    vector<uint> vec(3, 0);

    // *********************************
    // Case 1:
    //vec[currentIndex] = testFunc();

    // Case 2:
    //uint result = testFunc();
    //vec[currentIndex] = result;
    // *********************************

    cout << "currentIndex = "  << currentIndex << endl;
    cout << "vec = {" << vec[0] << ", " << vec[1] << ", " << vec[2] << "}" << endl;

    return 0;
}
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
alexirae
  • 35
  • 4

3 Answers3

4

C++11 introduces a model where certain operations are sequenced. For instance, when operation A is sequenced-before operation B, then A happens fully before B.

Now some operations may be sequenced, but in unspecified order. That means A happens either fully before B, or fully after. Case 1 is an example of that. The call to std::vector::operator[] is sequenced with respect to the call of testFunc, but their order is unspecified. Both are sequenced-before the assignment, but that is all you can say.

In case 2, you have sequential statements. Sequential statements are sequenced in the order they appear in, so the first statement fully completes before the second starts. This also means testFunc in the first statement completes before operator[] in the second statement starts.

MSalters
  • 173,980
  • 10
  • 155
  • 350
2

The short answer is: don't do this.

The more reasonable answer is: this is a matter of what is evaluated first: the indexing of the container or the function. In the second case this is well defined, in the first case not because a variable is changed and used without having a sequence point in between even if the variable is changed inside a function.

The reason for the short answer (don't do this) is that you make use of a global variable, you hide access/mutation of the global variable in an unrelated function and you call this function in the same statement where you use the variable as index.

stefaanv
  • 14,072
  • 2
  • 31
  • 53
  • I understand the "don't do this" reason, it is just an example :), in any case that could still happening inside a class with a member variable right? (and yes, I'm still thinking that is not a best practice, I'm aware of that, I'm curious about what and why this case gives 2 different results) – alexirae Oct 17 '17 at 08:08
  • The issue has to do with "sequence points" between which a compiler is free to reorder. I updated the answer and provided a link. – stefaanv Oct 17 '17 at 09:34
  • @stefaanv: Sequence points were a C++98 thing (see https://stackoverflow.com/a/4183735/15416 how it works now, or my answer for a short summary) – MSalters Oct 17 '17 at 09:58
1

In the first case, who knows when vec[currentIndex] is going to be evaluated? Before, or after testFunc() is called?

In contraty, the second case explicitly executes the steps needed, so that the flow of your program can be determined apriori (first the function is called, result is initialized`, then you evaluate both the expressions in the next line and proceed to the assigment).

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • Exactly, that's what I'm trying to figure out, will that decision be done by the compiler?, will that order change by some compiler optimization for example? – alexirae Oct 17 '17 at 08:07
  • 1
    Yes @alexirae, optimizations will lead to different compiler-produced code. The compiler decides, at its will, what will the order of execution be like. – gsamaras Oct 17 '17 at 08:07