代码之家  ›  专栏  ›  技术社区  ›  pasha

为什么文本和临时变量不是lvalue?

  •  8
  • pasha  · 技术社区  · 5 年前

    我读过,lvalues是“一个定义了存储位置的东西”。

    此外,文本和临时变量不是lvalues,但没有为此语句给出任何理由。

    是因为文本和临时变量没有定义存储位置吗?如果是,那么如果不在内存中,它们将驻留在哪里?

    我想“已定义的存储位置”中的“已定义”具有一定意义,如果存在(或不存在),请让我知道。

    4 回复  |  直到 5 年前
        1
  •  4
  •   NathanOliver    5 年前
    < Buff行情>

    此外,文本和临时变量不是lvalues,但没有为此语句给出任何理由。

    < /块引用>

    除字符串文本外,所有临时文本和文本都是如此。这些实际上是lvalues,解释如下。

    < Buff行情>

    是因为文本和临时变量没有定义存储位置吗?如果是,那么如果不在内存中,它们将驻留在哪里?

    < /块引用> 是的。文字 2 实际上不存在,它只是源代码中的一个值。因为它不是一个对象,它是一个值,所以它不必有任何相关的内存。它可以硬编码到编译器创建的程序集中,也可以放在某个地方,但是由于它不需要你做的所有事情,所以你可以把它当作一个纯粹的值,而不是一个对象。

    但是有一个例外,那就是字符串文本。因为字符串文字是 const char[N] . 您可以获取字符串文字的地址,字符串文字可以衰减为指针,因此它是左值,即使它没有名称。

    临时工也是临时工。即使对象存在,其存储位置也是短暂的。它只能持续到它们所在的完整表达式结束。你不能带他们的地址,他们也没有名字。例如,它们甚至可能不存在于

    Foo a = Foo();
    

    Foo() 可以删除代码,并将其语义转换为

    Foo a(); // you can't actually do this since it declares a function by that is the semantics it has.
    

    所以现在优化后的代码中甚至没有临时对象。

        2
  •  5
  •   YSC    5 年前
    < Buff行情>

    为什么文本和临时变量不是lvalue?

    < /块引用>

    我有两个答案:因为它没有意义(1),因为标准是这么说的(2)。让我们专注于(1)。

    < Buff行情>

    是因为文本和临时变量没有定义存储位置吗?

    < /块引用>

    这是一个不适合这里的简化。简化:文字和临时值不是lvalues,因为修改它们是没有意义的。

    什么意思 5++ ?什么意思 rand() = 0 ? 标准规定,临时和文字不是lvalues,因此这些示例无效。每一个编译器开发人员都更高兴。


    f(MyType{}.mutate()) 一方面 f(my_int + 1) 另一方面。我认为简化仍然是 MyType{}.mutate() 可以被视为 MyType{} 是,像 my_int + 1 可以被视为 int 作为 my_int 是。这都是基于语义和观点的。真正的答案是:(2)因为标准规定是这样的。

        3
  •  3
  •   Sergey Kalinichenko    5 年前
    < Buff行情>

    如果不在记忆中,它们会住在哪里?

    < /块引用>

    当然,它们存在于内存中,这是不可能的。问题是,您的程序能否确定它们在内存中的确切位置。换言之,您的程序是否允许获取相关内容的地址。

    在一个简单的例子中 a = 5 值为5,或表示值为5的赋值的指令在内存中的某个地方。但是,您不能取五个地址,因为 int *p = &5 是非法的。< / P >

    请注意,字符串文本是“非左值”规则的例外,因为 const char *p = "hello" 生成字符串文字的地址。


    但是,它可能不一定是数据。事实上,它们甚至不可能被表示为程序内存中的常量:例如,赋值 short a; a = 0xFF00 可以表示为 0xFF 在上八位字节中,清除内存中的下八位字节。
        4
  •  2
  •   roschach    5 年前

    lvalue 代表定位器值,表示占用内存中某些可识别位置的对象。

    还使用了“定位器值”一词 here

    < Buff行情>

    C

    C编程语言遵循类似的分类法,除了 分配的作用不再重要:C表达式 在“左值表达式”和其他表达式(函数和 非对象值),其中“lvalue”表示标识 一个对象,一个“定位器值”[4]。

    < /块引用>

    不是 lvalue的所有内容都是通过排除 rvalue . 每个表达式都是 lavalue rvalue->code>。

    最初,C中使用了 lvalue term来表示可以保留在赋值运算符左侧的值。但是有了 const 钥匙工作,这改变了。并非全部 lvalues 可以分配给。那些可以被称为 modifiable lvalues .

    < Buff行情>

    而且,文字和时间变量不是lvalue,而是 对此声明没有给出任何理由。

    < /块引用> 根据… this answer 在某些情况下,文字可以是 lvalues

    • 标量类型的字面值 are rvalue because very likely to be embedded directly into the machine commands on the given hardware architecture.
    • 相反,奇怪的是, string literals are lvalues because they have unexpectable size and there is no other way to representate them about from as objects in memory.
    • 根据相同的帖子,即使是陌生人, floating points are hidden lvalues >: < Buff行情>

      许多(如果不是大多数或全部)硬件架构浮点 文本实际上是作为“隐藏”的lvalue实现的(即使 语言不会暴露它们。在像x86机器这样的平台上 来自浮点组的命令不支持嵌入的immediate 操作数。这意味着实际上每个浮点文字都有 由编译程序存储在(或从)数据存储器中。例如当 你写的东西 i = i * 5.5 + 2.1 它被翻译成 有点像

      const double unnamed_double_5_5 = 5.5; 
      const double unnamed_double_2_1 = 2.1;
      i = i * unnamed_double_5_5 + unnamed_double_2_1; 
      

      换言之,浮点文字通常会变成“非官方的” lvalues内部。

    可以将 lvalue 转换为 rvalue 。例如,在以下说明中

    int a =5;
    int b = 3;
    int c = a+b;
    
    < P>算子 + 拿两个 rvalues . 所以 a b 在求和之前转换为 rvalues 另一个转换示例:

    int c = 6;
    &c = 4; //ERROR: &c is an rvalue
    

    相反, 您不能将 rvalue 转换为 lvalue >。

    但是,您可以从一个 rvalue 生成一个有效的 lvalue

    int arr[] = {1, 2};
    int* p = &arr[0];
    *(p + 1) = 10;   // OK: p + 1 is an rvalue, but *(p + 1) is an lvalue
    
    <>在C++ 11中,参考值与移动构造函数和移动赋值操作符有关。

    您可以在中找到更多详细信息 this clear and well-explained post