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

Temporary materialization conversion - Confusion about terminology and concepts

嗨,Whosebug 社区,

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

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

由于“临时”一词不够明确,我无法判断“临时具体化”是临时实现还是临时具体化。我认为是前者,但我不确定。另外:临时一词是否仅用于 class 类型?

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

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

根据 cppreference.com 所说的临时物化编号 1 和 2 是明确的案例(1:成员访问 class pravlue,2:绑定对纯右值的引用(如std::string +运算符).

不过,我不太确定第 3 个。 Cppreference 说:“请注意,当从相同类型的纯右值(通过直接初始化或复制初始化)初始化对象时,不会发生临时物化:此类对象直接从初始化器初始化。这确保了“保证复制省略”。 “ +operator returns 一个纯右值。现在,这个 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:什么是临时物化转换上下文中的临时项?这是否意味着临时物化或临时物化?还有temporary=临时对象?

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

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

temporary materialization应该是“物化的临时”的意思。老实说,我什至不知道“暂时的实体化”是什么意思。

术语临时不仅用于 class 类型。

宽泛地说,与 xvalues 不同,prvalues 不存在于内存中。你应该关心的是上下文。假设您已经定义了一个结构 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。其次,运算符 + 将绑定 onestd::string("Guaca") (新临时)的引用。 c_str() 的结果对象之一,但没有创建额外的临时对象,因为:。差不多就是这样。值得注意的是,创建临时对象的顺序是未知的——它完全是实现定义的。

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

Note that temporary materialization does not occur when initializing an object from a prvalue of the same type (by direct-initialization or copy-initialization): such object is initialized directly from the initializer. This ensures "guaranteed copy elision".

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

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