简体   繁体   中英

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?

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM