错误 C2106:'=':左操作数必须是 l 值

error C2106: '=' : left operand must be l-value

本文关键字:C2106 错误 操作数      更新时间:2023-10-16

看看关于错误C2106的其他问题,我仍然不知道我的代码有什么问题。在编译时,我得到以下错误:

c: \driver.cpp(99):错误C2106:"=":左操作数必须是l-value

c: \driver.cpp(169):错误C2106:"=":左操作数必须是l-value

代码行如下:

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

我不明白为什么会出现这个错误。在这个项目中,我将driver.cpp从一个雇员对象指针数组更改为我制作的自定义Vector模板。我声明向量如下。。。

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

任何帮助都将不胜感激。。。

引发此错误的原因与您不能执行以下操作的原因相同:

36 = 3;

您的Vector::at版本应该返回引用,而不是值
Lvalue之所以被称为Lvalue,是因为它们可以出现在赋值的左边。R值不能出现在左侧,这就是为什么我们称它们为右值。不能将3分配给36,因为36不是左值,而是一个右值,一个临时值。它没有内存地址。出于同样的原因,不能将NULL分配给payroll.at(i)


你的定义:

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

应该是什么:

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

消息说您试图分配给一个不是左值的表达式。对于内置类型,您只能分配给lvalues(这就是名称的来源:lvalue=可以位于赋值运算符的左侧的值,而rvalue=必须位于赋值运算符右侧右侧的值)。

那么什么是左值或右值呢?考虑以下代码:

int a;
a = 3;

在这个赋值中,a是一个左值(如果不是,编译器会抱怨)。也就是说,表达式a指的是可以被修改的对象。另一方面,3是一个右值,也就是说,基本上是一个值。当然,您不能分配给3;编译器会抱怨语句CCD_ 11与您在代码中得到的消息完全相同。

因此,作为第一近似,左值指定对象,而右值指定值。注意,对于表单的分配也是如此

a = b;

其中CCD_ 12也是一个变量。这里发生的是所谓的左值到右值的转换:分配的不是对象b,而是它的当前值。

现在考虑以下情况:

int f();
f() = 3;

在这里,您可能会争辩说函数f确实返回了一个对象(如果您使用某种用户定义的类型,您甚至可以看到它的构造/销毁)。但是编译器仍然会对您收到的消息进行抱怨。为什么?

好吧,即使您认为f返回一个对象,它也是一个临时对象,会立即消失。因此,分配一个值没有多大意义,因为之后无论如何都不能对它做任何事情。

因此,这里有第二条规则:

只要有一个表达式生成临时对象,C++就会将该表达式定义为右值。

现在我们来讨论MyVector::at()的定义,您没有显示它,但根据错误消息,它可能看起来像这样:

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

它的形式与上面的f基本相同,因为它还返回一个T(在您的情况下是employee*)。这就是编译器抱怨的原因。

这种抱怨是有帮助的:即使编译器不会抱怨,代码也不会说出你几乎可以肯定的意图。return语句返回对象data[i]副本。因此,如果payment.at(i)=NULL;已经编译了语句,那么实际会发生以下情况:

  1. 内部对象data[i](或您在代码中调用它的方式)被复制,并返回临时副本
  2. 指定临时复制的语句,但保持MyVector中的原始对象不变
  3. 临时副本会被销毁,不会留下您的作业痕迹

这几乎肯定不是你想要的。您想要更改内部对象。要做到这一点,您必须向该对象返回引用。引用引用的是初始化时使用的对象,而不是复制。相应地,引用,即使被返回,也是一个左值(由于C++11,还有第二种类型的引用表现不同,但我们在这里不需要关心这一点)。修正后的函数会读取

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

有了这个定义,payment.at(i)=NULL;不仅可以编译,而且可以实际执行您想要的操作:将payment中内部存储的第26个CCD_指针更改为NULL

您的函数MyVector::at(unsigned)可能没有正确声明,看起来像这样:

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

你想要的是它看起来像这样:

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

注意reference参数(&),它将通过引用返回任何元素,并允许表达式用作l值。

真正的问题是你为什么不使用std::vector

c++中的术语l-value表示"左值"的类型不正确。由于您在它上使用赋值运算符,因此要成为正确的类型,它必须是一个可以被赋予新值的值,这意味着它不能是常量。很可能,对payroll.at()的调用返回的是一个常数值,而不是对实际值的引用。尝试为其分配一个新值将导致l-value错误。