c++ 什么是纯右值表达式的“结果对象”?

1hdlvixo  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(112)

该标准在[basic.lval]/5中规定了以下内容:
[..]纯右值的结果对象是由纯右值[..]初始化的对象。
它与[basic.lval]/(1.2)中陈述的纯右值的定义同步:
纯右值是一个表达式,其计算结果是一个对象[..]
因此,据我所知,一个纯右值表达式的求值是一个名为“结果对象”的对象,而这个“结果对象”* 就是 * 这个纯右值初始化的对象。举例来说:

struct S {};

int main(void){
    S s = S();
}

这里S()是一个纯右值表达式,我认为s是它的结果对象(可能不正确,这就是我所要求的),因为根据第一个引号,s是由纯右值S()初始化的对象。现在,如果s实际上是结果对象,那么这里的结果对象在哪里:

struct X {};

int main(void){
     X();
}

这里X()纯右值没有结果对象,因为它没有被任何对象初始化;对不对?
当我在Clang AST中看到以下代码时,我陷入了这种困惑:(我很抱歉试图打开一个不相关的问题,但我会总结AFAIC)

struct Y {};

int main() { 
    Y y = Y(); 
}

下面是从上述代码生成的AST:(. omitted.)

....
...
`-FunctionDecl <line:5:1, line:7:1> line:5:5 main 'int ()'
  `-CompoundStmt <col:12, line:7:1>
    `-DeclStmt <line:6:5, col:14>
      `-VarDecl <col:5, col:13> col:7 y 'Y':'Y' cinit
        `-CXXTemporaryObjectExpr <col:11, col:13> 'Y':'Y' 'void () noexcept' zeroing

最后一行清楚地显示了创建了一个非实体化的临时get。当我试图理解为什么这个临时对象被创建时,无论正确与否,我检查了标准中的以下文本:([class.temporary]/3)

当类类型X的对象被传递到函数或从函数返回时,如果X至少有一个合格的复制或移动构造函数([special]),每个这样的构造函数都是平凡的,并且X的析构函数是平凡的或被删除的,实现允许创建一个临时对象来保存函数参数或结果对象

[..]
我不确定我是否找到了正确的段落。但如果是这样的话,上面的段落说创建的临时对象持有“结果对象”,我看到这里的结果对象是y;对吧,我有点困惑结果对象是y,而y尚未初始化?这里的结果对象是从构造函数调用产生的对象吗?还是别的什么
如果我的问题中有任何冲突,或者如果这些问题是基于误解,我道歉。

ldxq2e6h

ldxq2e6h1#

我认为s是它的结果对象
是的没错特别地,没有临时对象可以代替结果对象(从C17开始)。
这里X()纯右值没有结果对象,因为它没有被任何对象初始化;对不对?
表达式语句X();中的表达式X()是一个 * 带值表达式 * per [stmt.expr]/1。
在这里不相关的潜在转换之后,一个纯右值表达式是一个双值表达式,它按照[expr.context]/2应用临时物化转换。
临时物化转换的效果是引入一个临时对象,该对象是根据conv.rval(https://timsong-cpp.github.io/cppwp/n4868/conv.rval)的纯右值初始化的。
因此,这个临时对象是纯右值的结果对象。
当我在Clang AST中看到以下代码时,
CXXTemporaryObjectExpr可能(我在这里猜测)只表示T(E)形式的表达式,其中T是非引用类型,E是一个空表达式列表或两个或多个表达式的列表,并且不打算说明任何关于应用的临时物化转换的内容。
在C
17之前,这种语法通常会导致临时对象的创建(在可选的复制省略之前),这就是为什么这个名字有意义。从C17开始,在很多情况下,这个表达式语法不会像你演示的那样导致临时对象的创建。他们可能只是没有改变叮当内部命名。
你引用的标准与此无关,因为没有接受或返回S的函数。
请注意,以上内容仅适用于C
17及更高版本。

相关问题