首页 > 解决方案 > 临时物化转换 - 术语和概念的混淆

问题描述

嗨 stackoverflow 社区,

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

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

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

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

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

Kris van Rens 理解 C++ 中的值类别

根据 cppreference.com 关于临时实现编号的说法,1 和 2 是明确的情况(1:对类 pravlue 的成员访问,2:将引用绑定到纯右值(如在 std::string +operator 中)。

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

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

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

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

如您所见,我对整个主题感到很困惑。对我来说,掌握这些概念尤其困难,因为我在网上找不到以统一方式使用的各种术语的明确定义。我将不胜感激任何帮助!

最好的问候, 鲁珀尔特

TL;DR:什么是临时实现转换上下文中的临时?这是否意味着一个临时的物化了,或者它是暂时的物化?也是临时=临时对象?

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

标签: temporary-objectsvalue-categories

解决方案


107 次观看,6 个月,没有答案也没有评论。有趣的。这是我对你的问题的看法。

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

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

prvalues,松散地说,不像 xvalues 那样存在于内存中。你应该关心的是上下文。假设您已经定义了一个结构 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")(新临时)和一个到结果对象c_str(),但不会创建额外的临时,因为:

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

这意味着我们不再有“临时+移动/复制”阶段。prvalue 表示的对象现在将被构造到我们将使用构造函数移动/复制它的位置,以便创建一个临时对象。因此,如果编译器以前没有使用过 NRVO(此处的 RVO 没有意义) ,则无论运算符+返回什么都将立即用于构建。x

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


推荐阅读