临时物化转换——术语和概念的混乱

Rup*_*rrt 12 temporary-objects value-categories

你好 stackoverflow 社区,

我已经学习 C++ 几个月了,最近我一直在尝试掌握围绕“新”值类别、移动语义,尤其是临时物化的概念。

首先,如何解释“临时物化转换”这个词对我来说并不简单。转换部分对我来说很清楚(prvalue -> xvalue)。但在这种情况下,“临时”究竟是如何定义的呢?我曾经认为临时对象是仅存在的未命名对象 - 从语言的角度来看 - 直到评估它们所创建的表达式的最后一步。但这种概念似乎与临时对象的实际情况不符在临时物化、新价值类别等更广泛的背景下。

由于对“临时”一词缺乏明确性,导致我无法判断“临时物化”是临时物化还是临时物化。我认为是前者,但我不确定。另外:术语“临时”仅用于类类型吗?

这直接给我带来了下一个困惑:prvalues 和 xvalues 对于临时变量起什么作用?假设我有一个右值表达式,需要以必须将其转换为 xvalue 的方式进行计算,例如通过执行成员访问。究竟会发生什么?纯右值是否实际存在(在内存中或其他地方)并且纯右值是否已经是临时的?现在,“临时物化转换”被描述为“任何完整类型 T 的纯右值都可以转换为相同类型 T 的 xvalue。此转换通过使用临时对象评估纯右值,从纯右值初始化类型 T 的临时对象作为其结果对象,并生成一个表示临时对象的 xvalue”(https://en.cppreference.com/w/cpp/language/implicit_conversion)将纯右值转换为 xvalue。这段摘录让我认为纯右值是在内存或寄存器中任何地方都不存在的东西,直到它通过这种转换“具体化”为止。(另外,我不确定临时对象是否与临时对象相同。)因此,据我了解,此转换是通过对纯右值表达式进行求值来完成的,该表达式的结果是“真实”对象。然后,该对象由 xvalue 表达式表示(= 表示?)。记忆中发生了什么?右值在哪里,x值现在在哪里?

我的下一个问题是关于临时物化的某个部分的更具体的问题。在 Kris van Rens 在 YouTube ( https://www.youtube.com/watch?v=liAnuOfc66o&t=3576s ) 上大约 56:30 的演讲“Understanding valuecategories in C++”中,他展示了这张幻灯片:

了解 C++ 中的值类别 作者:Kris van Rens

根据 cppreference.com 关于临时物化的说法,数字 1 和 2 是明确的情况(1:类 pravlue 上的成员访问,2:将引用绑定到纯右值(如 std::string + 运算符中)。

不过,我对第三个不太确定。Cppreference 说:“请注意,当从相同类型的纯右值(通过直接初始化或复制初始化)初始化对象时,不会发生临时物化:此类对象是直接从初始化器初始化的。这确保了“保证复制省略”。 ” + 运算符返回纯右值。现在,这个 std::string 类型的纯右值用于初始化一个 auto(也应该解析为 std::string)变量。这听起来像是前面的 cppreference 摘录中讨论的情况。那么这里真的会出现临时实体化吗?由中间的 xvalue 表达式“表示”的对象(1 和 2)会发生什么情况?他们什么时候被摧毁?如果 + 运算符返回纯右值,它是否“存在”在某个地方?如果纯右值甚至不是真实的(物化?)对象,那么对象 auto x “直接从初始化器初始化”(纯右值)是如何实现的?

在 YouTube ( https://www.youtube.com/watch?v=-dc5vqt2tgA&t=2557s ) 约 40:00的演讲“没有什么比复制或移动更好 - Roger Orr [ACCU 2018]”中,几乎同样的例子:

没有什么比复制或移动更好的了

这张幻灯片甚至说,在初始化变量时会发生临时物化,这显然与上面的 cppference 的异常相矛盾。那么什么是真的呢?

正如你所看到的,我对整个话题感到非常困惑。对我来说,掌握这些概念尤其困难,因为我找不到在网上以统一方式使用的各种术语的任何明确定义。我非常感谢任何帮助!

最好的问候,鲁佩尔特

TL;DR:临时物化转换上下文中的临时是什么?这是否意味着暂时的物质化了,或者说物质化是暂时的?还有临时=临时对象?

在幻灯片中,3(第一张幻灯片)和 1(第二张幻灯片)真的是临时物化发生的点(与 cppreference 关于从相同类型的 pravlues 进行初始化的说法相冲突)吗?

Jam*_*oon 11

107 次浏览,6 个月,没有回复或评论。有趣的。这是我对你的问题的看法。

暂时物化应该是“暂时物化”的意思。

术语“临时”不仅仅用于类类型。

宽泛地说,纯右值与 xvalue 不同,不存在于内存中。你应该关心的是上下文。假设您已经定义了一个结构 struct S { int m; };

在表达式 中S x = S();,子表达式S()表示纯右值。编译器会像您编写的一样对待它S x{};(请注意,我故意添加了大括号,因为S x();实际上是函数的声明)。另一方面,在像 之类的表达式中int i = S().m;,子表达式S()是一个纯右值,它将被转换为 xvalue,也就是说,S()将表示内存中存在的内容。

关于你的第二个问题,你需要了解的是,在 C++-17 中,创建临时对象的情况已降至最低(cppreference 对此进行了很好的描述)。然而,表达

auto x = std::string("Guaca") + std::string("mole").c_str();

需要在赋值之前创建两个临时对象。首先,您正在使用方法进行成员访问,因此将创建c_str()一个临时对象。std::string其次,操作员+将绑定一个std::string("Guaca")(新临时)的引用。和 1 的结果对象c_str(),但没有创建额外的临时对象,因为:。差不多就这样了。值得注意的是,创建临时对象的顺序是未知的 - 它完全取决于编译器。

之后,我们调用该运算符,该运算符+可能会构造另一个运算std::string符,从技术上讲,该运算符不是临时对象,因为这是实现的一部分。该对象可能会也可能不会构建到内存位置中,x具体取决于 NRVO。在任何情况下,纯右值表达式std::string("Guaca") + std::string("mole").c_str()表示的任何值都将与该表达式表示的值(同一对象的)相同,x因为cpp.ref

请注意,当从相同类型的纯右值(通过直接初始化或复制初始化)初始化对象时,不会发生临时物化:此类对象是直接从初始化器初始化的。这确保了“保证复制省略”。

这句话并不准确,可能会让您感到困惑,所以我还建议阅读复制省略(关于强制省略的第一部分)。

我不是 C++ 专家,所以对所有这些持保留态度。