What does the "=" operator return?

From what I understand, C ++ works from left to right. For example, if I:

std::cout << "output" << "stream"; 

C ++ first starts with the leftmost one (std :: cout), and then a <<statement appears that takes the string literal to the right ("output") and places it in the object to the left of the operator (std :: cout). Then C ++ returns the object to the left of the operator (std :: cout), and then continues the code, another <<Operator.

What does the "=" operator return?

If i do

 double wage = 5; double salary = wage = 9999.99; 

I thought that the operator "=" would return only the left or right operand "=". So, with my logic, in the salary initialization line, the salary is initialized with the salary value, then the = operator returns either the salary or the salary (let them say the salary), then it assigns 9999.99 to the salary, but the salary is gone, it must save the value 5 .

But when I check the salary and salary values โ€‹โ€‹after the salary initialization, both have a value of 9999.99. If I apply the same logic that I used with std :: cout above, there should be only one variable: "salary" or "salary" with a value of 9999.99

+7
c ++
source share
4 answers

The assignment operator from right to left is associative and, generally speaking, returns its left operand by reference. Generally speaking, this is true for all built-in types, library types that I can think of, and how you should write assignment operators.

It means that

 double salary = wage = 9999.99; 

Just like

 wage = 9999.99; double salary = wage; 

Note that in the second line here, salary set to wage , not 9999.99 . The difference does not matter here, but in some cases it is possible. For example (e.g. thanks to Justin Time):

 double salary = --(wage = 9999.99); 

salary obviously gets the value 9998.99 independently, but it's important to note that wage does as well; if the assignment returns the correct argument, instead wage will still have the value 9999.99, because the temporary value will decrease after the assignment to the wage.

As Ben Voigt notes in the comments below, although my answer is correct, the example from the question I am using is a bit misleading. This is due to the fact that despite the fact that the token = displayed twice in the code in question, double salary = wage = 9999.99 does not actually call the assignment twice, but rather calls the assignment and then creates a new double. The example will be better continued as follows:

 double salary = 0.0; salary = wage = 9999.99; 

Now we really bind the assignment operators, and all of my previous comments on priorities and returns apply to the second line of code here.

+17
source share

Refer to the operator priority table . The assignment operator = is a right-to-left association. Thus, the expression is effectively evaluated as:

 double salary = (wage = 9999.99); 

When wage = 9999.99 happens first.

+3
source share

Expressions matter and a side effect. The value (that you call "return") is what will be used for another statement for which this expression is an operand. (It is still calculated, even if there is no such operator). The process of finding the value of an expression is called calculating the value.

Value can have any category. A side effect is everything that happens, such as updating a memory location or calling a function.

In general, a side effect may or may not occur before the value is used in a larger subexpression. It is known that the postfix- ++ operator can have a rather large time difference between the value and the side effect.

For assignment expressions, the value is the left operand (with the category value "lvalue"), and the side effect is that the object assigned by the left operand is updated to hold the value of the right operand; and the side effect is sequenced before calculating the value, which ensures that if a larger expression uses this value, it denotes the memory cell that already received the new value stored in it.

If the code was:

 salary = wage = 9999.0; 

then the rules of operator associativity mean that it is salary = (wage = 9999.0); . The internal expression has the value wage with the value of the lvalue category, and the side effect of the internal expression is that it stores a variable named wage gets 9999.0 , and the sequence of assignment operators ensures that the result is already stored there before we move on to the next external expression.

Then we have salary = X , where X is the value described in the previous paragraph, that is, it is equivalent to salary = wage;


Please note that your actual code is a declaration, and the first = character in the declaration is not an assignment operator. Instead, it is the grammatical marker in which the initializer comes; your code will be the same as:

 double salary { wage = 9999.0 }; 
+1
source share

In your example

 double wage = 5; double salary = wage = 9999.99; 

& hellip; there is only one purpose , namely

 wage = 9999.99 

Other instances = are part of the initialization syntax.

The destination returns a reference to the object to which the value is assigned, in this case wage . So the example is equivalent

 double wage = 5; wage = 9999.99; double salary = wage; 

If your example is rewritten to use several purposes,

 double wage; double salary; wage = 5; salary = wage = 9999.99; 

& hellip; it becomes important that assignment operators are right-associative. So the last line is equivalent

 salary = (wage = 9999.99); 

& hellip; where the expression in parentheses returns a link to wage .


Standard containers require the user assignment operator to return a reference to the assigned object. The main language does not have this requirement, so it may be tempting to use void . That is, guaranteed efficiency that does not support unholy code based on side effects and a more concise implementation, all of which are good:

 struct S { void operator=( S ); // OK with respect to core language rules. }; 

However, in order for the delete or default assignment operator, the operator declaration must give it a reference return type:

 struct T { auto operator=( T const& ) -> T& // But `void` won't work here. = delete; }; 

On the third and exciting hand, a detailed, not guaranteed-effective and non-competitive-side-effect-code operator= can be expressed in terms of a separate void member function, which can even be an operator:

 struct U { void assign( U other ); auto operator=( U const& other ) -> U& { assign( other ); return *this; } }; 
+1
source share

All Articles