在C ++中,所有的临时都是rvalues吗?

时间:2010-01-27 06:43:16

标签: c++ rvalue temporaries

过去几年我一直用C ++编写代码。但有一个问题我无法弄清楚。我想问一下,C ++,rvalues都是临时的吗?

如果不是,有人可以提供一个示例,其中代码中的临时生成是左值吗?

7 个答案:

答案 0 :(得分:43)

没有

C ++语言规范永远不会像你要问的那样直截了当地断言。它并没有在语言标准中的任何地方说“所有临时对象都是右值”。此外,问题本身有点用词不当,因为作为C ++语言中的右值的属性不是对象的属性,而是表达式的属性(即其结果的属性)。这实际上就是它在语言规范中的定义:对于不同类型的表达式,当结果是左值时,它表示为右值。除此之外,这实际上意味着临时对象可以作为右值和左值访问,具体取决于用于执行访问的特定表达形式。<​​/ p>

例如,文字2 + 3表达式的结果显然是右值,是int类型的临时值。我们无法将一元&应用于它,因为一元&需要左值作为其操作数

&(2 + 3); // ERROR, lvalue required

但是,众所周知,常量引用可以附加到临时对象,如

const int &ri = 2 + 3;

在这种情况下,引用附加到临时引用,延长后者的生命周期。显然,一旦完成,我们就可以访问与左值ri完全相同的临时值,因为引用总是左值。例如,我们可以轻松合法地将一元&应用于引用并获取指向临时的指针

const int *pi = &ri;
只要暂时持续存在,

指针保持完全有效。

lvalue访问临时对象的另一个明显例子是当我们通过其this指针访问类类型的临时对象时。 *this的结果是左值(对于应用于数据指针的一元*的结果总是如此),但它并没有改变实际对象可能很容易成为一个事实的事实。临时。对于给定的类类型T,表达式T()是一个rvalue,如语言标准中明确指出的那样,但是通过*T().get_this()表达式访问的临时对象(具有明显的{{1}实现}}是一个左值。与前面的示例不同,此方法允许您立即获取非const限定的左值,该左值引用临时对象。

因此,同样的,临时对象可能很容易被“看作”为右值或左值,具体取决于您使用的表达式(访问路径的类型)看看那个对象。

答案 1 :(得分:9)

Prasoon Saurav已经联系了一个非常好的clc ++线程。在那里,James Kanze解释了为什么这个问题没有意义。归结为:

  • rvalue-ness是表达式的(boolean)属性 - 每个表达式都是左值或右值
  • 临时表不是表达式

因此,这个问题没有意义。

一个很好的例子是以下代码:

int main() {
  const int& ri = 4;
  std::cout << ri << std::endl; 
}

值为4的临时int不是表达式。打印的表达式ri不是临时的。这是一个左值,指的是临时的。

答案 2 :(得分:1)

好吧,那个数组运算符返回一个引用,任何返回引用的函数都可以被认为是做同样的事情?所有引用都是const,虽然它们可以是左值,但它们会修改它们引用的内容,而不是引用本身。 *运算符

也是如此

*(a temp pointer) = val;

我发誓我过去常常使用一些编译器将临时值传递给任何带参考的函数,

所以你可以去:

int Afunc()
{
   return 5;
}

int anotherFunc(int & b)
{
    b = 34;
}


anotherFunc(Afunc());

现在找不到允许你这样做的,但引用必须是const才能允许传递临时值。

int anotherFunc(const int & b);

无论如何,引用可以是左值和临时值,诀窍是引用它的自身不被修改,只有引用它。

如果将->运算符计为运算符,则临时指针可以是左值,但是应用相同的条件,它不是可以更改的临时指针,而是指向它的东西。

答案 3 :(得分:0)

数组索引操作既是临时值也是左值,类似[10] = 1就是你要找的东西的一个例子;左值是一个临时的计算指针。

答案 4 :(得分:0)

这取决于你认为临时变量是什么。你可以写点像

#include <stdio.h>
int main()
{
    char carray[10];
    char *c=carray+1;
    *(c+2+4) = 9;
    printf("%d\n",carray[7]);
    return 0;
}

这在VisualStudios和GCC中运行。您可以在codepad

中运行代码

我认为(c + 2 + 4)是一个右值,虽然我想分配给它。当我取消引用它时,它将成为左值。所以,所有的临时都是rvalues。但是你可以通过解除引用来使rvalues(因此是临时的)成为左值

答案 5 :(得分:0)

简短回答:是的,但我不会引用标准,因为要证明这一点需要解决各种临时问题。根据定义,临时具有一个语句的生命周期,因此将事物分配给一个语句充其量只是风格不佳。

有趣的答案:复制省略可以使(通常是)与左值对象相同的临时对象。例如,

MyClass blah = MyClass( 3 ); // temporary likely to be optimized out

return MyClass( 3 ); // likely to directly initialize object in caller's frame

编辑关于在这些情况下是否有任何临时对象的问题,§12.8/ 15提及

  

通过将临时对象直接构造到省略副本的目标

中,可以省略复制操作

表示存在可能与左值相同的临时对象。

答案 6 :(得分:-3)

  

如果不是,任何人都可以提供一个示例,其中代码中临时生成的是左值?

以下代码绑定对编译器创建的const float类型的临时对象的常量引用:

int i;
const float &cfr = i;

行为是“,好像”:

int i;
const float __tmp_cfr = i; // introduced by the compiler
const float &cfr = __tmp_cfr;