Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ assignment side-effect

While trying to ensure ascending order of two variables, I've encountered strange anomaly in Visual Studio 2012 C++ compiler that can be illustrated by the following code snippet

    double x1 = 2;
    double x2 = 1;
    std::tie(x1, x2) = std::minmax(x1, x2);
    std::cout << "x1 = " << x1 << ",   x2 = " << x2 << "\n";

one would expect that x1 is 1 and x2 is 2. But they are not. Instead

    //output:
    //x1 = 1,   x2 = 1

Is there any good explanation, just to be sure not to fall into similar trap again?

like image 456
Alex B. Avatar asked Jun 29 '13 13:06

Alex B.


People also ask

Does C have side effects?

When taken by mouth: Vitamin C is likely safe for most people. In some people, vitamin C might cause side effects such as stomach cramps, nausea, heartburn, and headache. The chance of getting these side effects increases with higher doses.

What is C assignment?

There are different kinds of the operators, such as arithmetic, relational, bitwise, assignment, etc., in the C programming language. The assignment operator is used to assign the value, variable and function to another variable.

What is persistent side effects in C?

Definition of persistent side effect: "A side effect is said to be persistent at a particular point in execution if it might have an effect on the execution state at that point." [Reference: Misra C, Appendix J] c. volatile. misra.

What is a side effect in a program?

A side effect is when a function relies on, or modifies, something outside its parameters to do something. For example, a function which reads or writes from a variable outside its own arguments, a database, a file, or the console can be described as having side effects.


2 Answers

std::minmax returns its arguments back by reference. What happens with your statement is, first x1 gets assigned the value of x2, which is 1. Then, x2 gets assigned the value of x1, which was 2, but is now 1.

If you were to inline everything, it might look something like this:

// using pointers because references can't be rebound
double *less, *greater;

if (x1 <= x2)
{
    less = &x1;
    greater = &x2;
}
else
{
    // in your case, this is the branch taken
    less = &x2;
    greater = &x1;
}

x1 = *less;       // less points to x2, so now both x1 and x2 = 1
x2 = *greater;    // greater points to x1, and x1 = 1, so this assignment is redundant

I think part of your confusion comes from thinking (or hoping) that the assignments would happen simultaneously, but they don't. When you assign a tuple or a pair, the sub-objects are assigned in order, from left to right.

like image 88
Benjamin Lindley Avatar answered Oct 27 '22 20:10

Benjamin Lindley


The problem is that std::minmax() accepts two references and returns a pair of references. In particular, in your case it will return a pair where the first element is a reference to x2, and the second element is a reference to x1.

On the left side of the assignment, on the other hand, you have:

std::tie(x1, x2)

Which also creates a pair of references (ok, a tuple of two references actually, but that doesn't matter), but this time the first element of the pair is a reference to x1, while the second element is a reference to x2.

Then, you assign the pair returned by std::minmax() to the pair returned by std::tie, which means that x1 gets assigned the value of x2 (which is 1) first; after that, x2 gets assigned the new value of x1 (once again, that's because std::minmax() returned a pair of references, so the second element of that pair "sees" the side-effect of the assignment to x1), which is now 1.

This should explain the output.

like image 37
Andy Prowl Avatar answered Oct 27 '22 21:10

Andy Prowl