Error C2106: '=': the left operand must be l-value

Looking at other issues regarding error C2106, I still lose what the problem is with my code. When compiling, I get the following errors:

c: \ driver.cpp (99): error C2106: '=': the left operand must be l-value

c: \ driver.cpp (169): error C2106: '=': the left operand must be l-value

The line of code is as follows:

payroll.at(i) = NULL; //Line 99 payroll.at(count++) = ePtr; //Line 169 

I do not understand why this error occurs. In this project, I changed my driver.cpp from an array of pointers to a worker object to a custom vector template that I created. I declare the vector as follows:

 //Declare an Vector to hold employee object pointers MyVector <employee*> payroll; 

Any help is appreciated ...

+3
source share
4 answers

This error occurs for the same reason that you cannot do something like this:

 36 = 3; 

Your version of Vector::at should return a link, not a value.
Lvalues โ€‹โ€‹are called Lvalues โ€‹โ€‹because they can appear to the left of the assignment. Rvalues โ€‹โ€‹cannot appear on the left side, so we call them rvalues. You cannot assign 3 to 36 because 36 not an lvalue, it is an rvalue, temporary. It does not have a memory address. For the same reason, you cannot assign NULL payroll.at(i) .


Your definition:

 template <class V> V MyVector<V>::at(int n) 

What it should be:

 template<typename V> V& MyVector::at(std::size_t n) template<typename V> const V& MyVector::at(std::size_t n) const 
+12
source

The message says that you are trying to assign an expression that is not an lvalue value. For built-in types, you can only assign lvalues โ€‹โ€‹(where the name occurs: lvalue = the value that can be on the left side of the assignment operator, while rvalue = the value that should be on the right side of the assignment operator).

So what is lvalue or rvalue? Consider the following code:

 int a; a = 3; 

In this assignment, a is the value of lvalue (if it werenโ€™t, the compiler will complain). That is, the expression a refers to an object that can be modified. On the other hand, 3 is the value of r, that is, basically the value. Of course you cannot assign 3 ; the compiler will complain about 3=a; with the same message you received in your code.

So, in a first approximation, lvalue denotes an object, and rvalue denotes a value. Note that this is also true for form assignment.

 a = b; 

where b also a variable. Here the so-called conversion of lvalue to rvalue occurs: not the object b assigned, but its current value.

Now consider the following case:

 int f(); f() = 3; 

Here you can argue that the function f returns an object (if you use a specific user type, you can even see its construction / destruction). But the compiler is still complaining about your message. Why?

Well, even if you think f returns an object, it is a temporary object that will disappear immediately. Therefore, it makes no sense to assign a value, because after that you can do nothing with it.

Therefore, here is the second rule:

Whenever there is an expression that creates a temporary object, C ++ defines this expression as an rvalue.

And now we move on to the definition of MyVector::at() , which you did not show, but which, according to the error message, looks something like this:

 template<typename T> T MyVector<T>::at(int i) { return data[i]; } 

This is essentially the same kind as f above, since it also returns T (an employee* in your case). This is why the compiler complains.

And this complaint is useful: even if the compiler does not complain, the code will not do what you almost certainly planned. The return returns a copy of the data[i] object. Thus, if the command payment.at(i)=NULL; was compiled, what would actually happen, would be the following:

  • The internal data[i] object (or, nevertheless, you called it in the code) is copied and a temporary copy is returned.
  • The statement assigns this temporary copy, but the original object in MyVector does not change.
  • The temporary copy is destroyed, leaving no trace of your destination.

This is almost certainly not what you wanted. You want to change the internal object. To do this, you need to return a link to this object. The reference refers to the object that was initialized, instead of making a copy. Accordingly, a link, even when it returns, is an lvalue value (since C ++ 11 contains a second type of link that behaves differently, but we donโ€™t need to take care here). Then your fixed function reads

 template<typename T> T& MyVector<T>::at(int i) { return data[i]; } 

and with this definition payment.at(i)=NULL; not only compiles, but also does what you want: change the internally stored i pointer in payment to NULL .

+5
source

Your function MyVector::at(unsigned) is probably incorrectly declared and looks like this:

 T MyVector::at(unsigned i) { /* implementation detail */ } 

What you want is to look like this:

 T& MyVector::at(unsigned i) { /* implementation detail */ } 

Pay attention to the reference parameter (&), which will return any element by reference and allow the expression to be used as an l-value.

The real question is: why aren't you using std::vector instead?

+3
source

the term l-value in C ++ means that "left-value" is of the wrong type. Since you use the assignment operator on it to be the correct type, it must be a value to which a new value can be assigned, which means that it cannot be a constant. Most likely, your call to payroll.at() returns a constant value instead of a reference to the actual value. Attempting to assign a new value to it will result in an l-value error.

0
source

Source: https://habr.com/ru/post/1015406/


All Articles