【问题标题】:Is a function call returning a pointer to an object a prvalue?函数调用返回指向对象的指针是纯右值吗?
【发布时间】:2020-07-02 08:58:53
【问题描述】:

让我们想象一下这个函数:

C* get(C* c, int offset) {
    return c + offset;
}

我想知道对该函数的调用是否被评估为纯右值:

C array_c[3];
C* c2 = get(array_c, 2);

get(array_c, 2) 是纯右值吗?

根据cppreference上的Value categories页面:

  • glvalue(“广义”左值)是一个表达式,其评估确定对象、位域或函数的身份;
  • a prvalue(“纯”右值)是一个表达式,其求值是:
    • 计算与对象无关的值
    • 创建一个临时对象并表示它
  • 一个xvalue(一个“eXpiring”值)是一个glvalue,它表示一个对象或位域,其资源可以被重用;
  • lvalue(所谓的,历史上,因为左值可能出现在赋值表达式的左侧)是不是 xvalue 的左值;

在我们的示例中,表达式get(array_c, 2) 指向一个已经存在的对象,该对象在调用后不会过期。所以我们可以说它是一个左值。此外,我们可以写*get(array_c, 2) = C{};给表达式赋值。

但是,有两点让我认为它不是左值。首先在cppreference的同一个页面:

以下表达式是纯右值表达式:

  • 函数调用或重载的运算符表达式,其返回类型为非引用

在我们的示例中,get 函数返回一个非引用,因此根据这个定义,调用应该被评估为纯右值。

另外,我想知道get(array_c, 2) 是否确实是一个临时的,使它成为一个prvalue,而*get(array_c, 2) 是一个左值,因为我们可以为它分配一个值。

你怎么看?函数调用是否被评估为左值、纯右值(或其他)?

【问题讨论】:

    标签: c++ language-lawyer value-categories


    【解决方案1】:

    get(array_c, 2)*get(array_c, 2) 是两个不同的表达式,具有不同的值类别。

    get 本身按值返回指针,则get(array_c, 2) 被视为右值(prvalue)表达式。你不能像get(array_c, 2) = nullptr;那样对其进行赋值,也不能像&get(array_c, 2)那样从中获取地址,就像get返回其他类型一样,比如int

    另一方面,*get(array_c, 2)lvalue expression。正如你所说,你可以对其进行赋值,有效与否,返回的指针有效与否无关紧要。

    *p,内置indirection表达式;


    PS:赋值可能在类类型的右值上执行;不是判断左值表达式的绝对条件。

    【讨论】:

    • 我认为你不应该以赋值为例,因为它可以在类类型的右值上完成。
    • @jrok 你是对的。我保留它是因为 OP 提到了它(所以它可能有助于 OP 理解)并且对于 OP 代码中的内置类型也是如此。
    【解决方案2】:

    get(array_c, 2)*get(array_c, 2)不是同一个表达式;它们不必都属于同一个值类别。

    get(array_c, 2) 是纯右值。

    以下表达式是prvalue表达式

    ...

    • 函数调用或重载的运算符表达式,其返回类型为非引用...

    *get(array_c, 2) 是一个左值。

    以下表达式是左值表达式

    ...

    • *p,内置间接表达式;

    (Source)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-10
      • 2017-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-21
      • 2011-01-12
      相关资源
      最近更新 更多