POD,非POD,右值和左值

时间:2010-02-19 02:54:33

标签: c++ pod lvalue rvalue

有人可以解释rvalues,左值,POD和非POD方面的详细信息,下面标记的第一个表达式 ok,而下面标记的第二个表达式正常吗?在我的理解中,int()和A()都应该是rvalues,不是吗?


struct A {};

int main()
{
  int i;
  A a;

  int() = i; //Not OK (error).
  A() = a; //OK.

  return 0;
}

3 个答案:

答案 0 :(得分:19)

Rvalues是你从表达式中得到的(一种有用的简化,取自C标准,但在C ++标准中没有措辞)。左值是“定位器值”。左值可以用作右值。引用总是左值,即使是const。

您必须知道的主要区别可以压缩为一个项目:您不能获取右值的地址(同样,不是标准,而是规则的有用概括)。换句话说,你不能为rvalue修复精确的位置 - 如果可以,那么你就有了一个左值。 (但是,您可以将const&绑定到右值以“将其固定到位”,并且0x正在大幅改变规则。)

然而,用户定义的类型(UDT)有点特殊:如果类的接口允许,您可以将任何右值转换为左值:

struct Special {
  Special& get_lvalue() { return *this; }
};
void f() {
  // remember "Special()" is an rvalue
  Special* p = &Special().get_lvalue(); // even though you can't dereference the
  // pointer (because the object is destroyed), you still just took the address
  // of a temporary

  // note that the get_lvalue() method doesn't need to operate on a const
  // object (though that would be fine too, if the return type matched)
}

除了通过编译器提供的赋值运算符之外,A() = a发生了类似的事情,将右值A()转换为*this。引用标准,12.8 / 10:

  

如果类定义未显式声明复制赋值运算符,则会声明隐式。类X的隐式声明的复制赋值运算符将具有

形式
X& X::operator=(const X&)

然后它继续提供更多的资格和规格,但这是重要的一点。由于这是一个成员函数,它可以在rvalues上调用,就像Special :: get_lvalue一样,就像你写了A().operator=(a)而不是A() = a一样。

您发现int() = 1被明确禁止,因为int没有以相同的方式实现operator =。但是,类型之间的这种轻微差异在实践中并不重要(至少不是我发现的)。


POD表示普通旧数据,是指定使用memcpy的要求集合等同于复制。非POD是你不能使用memcpy复制的任何类型(与POD完全相反,这里没有任何隐藏),这往往是你用C ++编写的大多数类型。作为POD或非POD不会改变上述任何一个,并且实际上是一个单独的问题。

答案 1 :(得分:2)

  

在我的理解中,int()和A()都应该是rvalues,不是吗?

正确,epxression T()始终是标量和用户定义类型T的右值。只要不涉及const,表达式T()就是可修改的右值,更准确一些。

涉及标量类型的赋值需要在赋值运算符的左侧有一个可修改的左值。由于int()不是左值,因此您无法分配到int()

对于用户定义的类型,赋值是一个特殊的成员函数,也可以在 rvalues 上调用成员函数(参见§3.10第10节)。这就是A().operator=(a)形成良好的原因。

答案 2 :(得分:1)

来自Does C++ do value initialization of a POD typedef?,引用标准:

  

表达式T(),其中T是a   a的简单类型说明符(7.1.5.2)   非数组完整对象类型或   (可能是cv-qualified)void类型,   创建指定的右值   type,值初始化

因此,int()是一个右值,无法分配,如第一种情况所示。

A()不是一个simlle-type-specifyer,因此A()产生一个左值