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

KQb*_*all 5 c++ templates vector

看看有关错误C2106的其他问题,我仍然对代码的问题感到遗憾.在编译时我收到以下错误:

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

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

代码行如下:

payroll.at(i) = NULL; //Line 99
payroll.at(count++) = ePtr; //Line 169
Run Code Online (Sandbox Code Playgroud)

我无法理解为什么会抛出这个错误.在这个项目中,我将driver.cpp从一组员工对象指针更改为我制作的自定义Vector模板.我将Vector声明如下......

//Declare an Vector to hold employee object pointers
MyVector <employee*> payroll;
Run Code Online (Sandbox Code Playgroud)

任何帮助表示赞赏......

Moh*_*oun 12

抛出此错误的原因与您无法执行此操作的原因相同:

36 = 3;
Run Code Online (Sandbox Code Playgroud)

您的版本Vector::at应该返回引用而不是值.
左值称为左值,因为它们可以出现在赋值的左侧.Rvalues不能出现在左侧,这就是我们称之为rvalues的原因.你不能分配3,36因为36它不是左值,它是一个右值,一个临时值.它没有内存地址.出于同样的原因,你不能分配NULLpayroll.at(i).


你的定义:

template <class V> V MyVector<V>::at(int n)
Run Code Online (Sandbox Code Playgroud)

应该是什么:

template<typename V> V& MyVector::at(std::size_t n)
template<typename V> const V& MyVector::at(std::size_t n) const
Run Code Online (Sandbox Code Playgroud)

  • @LewsTherin你是对的,但这是向量的自定义实现 (3认同)
  • 好吧,我正在查看文档,它说它返回一个引用..你确定吗? (2认同)

cel*_*chk 5

消息说您尝试分配给不是左值的表达式.对于内置类型,则只能分配给左值(这就是这个名字来源于:左值=值可以在左侧的赋值运算符的右手边,而右值=值必须在右边的右手边赋值运算符).

那么左值或左值是多少?请考虑以下代码:

int a;
a = 3;
Run Code Online (Sandbox Code Playgroud)

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

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

a = b;
Run Code Online (Sandbox Code Playgroud)

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

现在考虑以下情况:

int f();
f() = 3;
Run Code Online (Sandbox Code Playgroud)

在这里你可能会争辩说函数f会返回一个对象(如果你使用一些用户定义的类型,你甚至可以看到它的构造/破坏).但编译器仍然抱怨你得到的消息.为什么?

好吧,即使您考虑f返回一个对象,它也是一个临时对象,它会立即消失.因此,分配一个值没有多大意义,因为无论如何你都无法对它做任何事情.

因此,这是第二条规则:

只要有一个表达式产生一个临时对象,C++就会将该表达式定义为rvalue.

现在我们来看MyVector::at()你没有展示的定义,但根据错误信息,它可能看起来与此类似:

template<typename T>
 T MyVector<T>::at(int i)
{
  return data[i];
}
Run Code Online (Sandbox Code Playgroud)

这与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];
}
Run Code Online (Sandbox Code Playgroud)

并且使用该定义,payment.at(i)=NULL;不仅可以编译,而且可以实际执行您想要的操作:将内部存储的i-th指针更改paymentNULL.