当前位置: 首页 > 知识库问答 >
问题:

初始化是否需要LValue到RValue的转换?是否`int x=x;`UB?

叶允晨
2023-03-14

C++标准在3.3.2“声明点”中包含了一个半著名的“令人惊讶的”名称查找示例:

int x = x;

这会用它自己初始化x,它(作为一个基元类型)是未初始化的,因此具有一个不确定的值(假设它是一个自动变量)。

共有1个答案

申屠飞
2023-03-14

更新:在评论中的讨论之后,我在这个答案的末尾添加了一些更多的证据。

免责声明:我承认这个答案是相当投机的。另一方面,目前C++11标准的制定似乎不允许有一个更正式的答案。

在本问答的上下文中,C++11标准没有正式规定每个语言结构所期望的值类别。在下面,我将主要关注内置运算符,尽管问题是关于初始化器的。最后,我将把我在运算符的情况下得出的结论扩展到初始化器的情况。

因此,函数调用不应在LValue到RValue的转换和与任何单个复合赋值运算符相关联的副作用之间进行干预

当然,如果没有预期的rvalue,这个注释将毫无意义。

另一个证据在4/8中找到,正如约翰内斯·肖布在链接问答的评论中指出的那样:

通常的lvalue到rvalue(4.1)、数组到指针(4.2)和函数到指针(4.3)标准转换是不需要的,因此,当直接绑定到lvalue时,这些转换被禁止。

“通常”这个词似乎意味着,当初始化不属于引用类型的对象时,应该应用lvalue-to-rvalue转换。

因此,我认为,尽管对初始值设定项的期望值类别的要求不明确(如果不是完全缺失的话),但根据所提供的证据,假设预期的规范如下是有意义的:

补充证据:

为了提供进一步的证据来支持这一猜想,让我们假设它是错误的,因此复制初始化确实不需要LValue到RValue的转换,并考虑以下代码(感谢jogojapan的贡献):

int y;
int x = y; // No UB
short t;
int u = t; // UB! (Do not like this non-uniformity, but could accept it)
int z;
z = x; // No UB (x is not uninitialized)
z = y; // UB! (Assuming assignment operators expect a prvalue, see above)
       // This would be very counterintuitive, since x == y

这种不统一的行为对我来说没有太多意义。IMO更有意义的是,只要需要一个值,就需要一个prvalue。

    null

关于第二个问题,正如答案的最初部分所讨论的,C++11标准目前没有指定是否需要类别转换,因为没有提到复制初始化是否需要prvalue作为初始值设定项。因此,不可能给出明确的答案。然而,我相信我提供了足够的证据来假设这是预期的规范,所以答案将是“是”。

至于第一个问题,在我看来,答案也是“是”是合理的。如果是“不”,显然正确的程序将是错误的:

int y = 0;
int x = y; // y is lvalue, prvalue expected (assuming the conjecture is correct)

概括起来(A1=“回答问题1”,A2=“回答问题2”):

          | A2 = Yes   | A2 = No |
 ---------|------------|---------|
 A1 = Yes |     UB     |  No UB  | 
 A1 = No  | ill-formed |  No UB  |
 ---------------------------------

[...]此外,4.1[conv.lval]第1段指出,将lvalue-to-rvalue转换应用于“未初始化的对象”会导致未定义的行为;这应该用一个不确定值的对象来重新措辞。

特别是,第4.1段的拟议措词是:

当在未计算的操作数或其子表达式中发生LVALUE到RVALUE转换时(子句5[expr]),将不访问引用对象中包含的值。在所有其他情况下,转换的结果根据以下规则确定:

-否则,如果T是(可能是CV限定的)无符号字符类型(3.9.1[basic.basitic]),并且glvalue引用的对象包含一个不确定值(5.3.4[expr.new]、8.5[dcl.init]、12.6.2[class.base.init]),并且该对象没有自动存储持续时间,或者glvalue是一元&运算符的操作数,或者它绑定到引用,则结果是一个未指定的值。[脚注:每次对对象应用LVALUE到RVALUE转换时,值可能不同。分配给寄存器的值不确定的无符号char对象可能会陷阱。-结束脚注]

-否则,如果glvalue引用的对象包含不确定值,则行为未定义

-否则,如果glvalue具有(可能是CV限定的)类型STD::NULLPTR_T,则prvalue结果为空指针常量(4.10[conv.ptr])。否则,glvalue指示的对象中包含的值是prvalue结果。

 类似资料:
  • 我正在使用mockito作为junit。在创建对象的模拟时,我有疑问。我有一个名为DBConnect的类。我需要数据库属性,如dbname、凭据等。PatientDetails使用这个类。现在,当我为PatientDetails编写junit时。所以我使用以下代码。 用这个我不能得到正确的结果。

  • 我将firebase添加到我的android项目中,以使用firebase云消息传递。我按照文档进行了操作,但没有找到调用的任何说明。 我的应用程序工作很好,除了有一次它崩溃了以下错误。 当我搜索错误时,给出的解决方案是在启动时调用。 我想知道这是否真的有必要,因为文档没有提到它,我的应用程序在没有它的情况下工作(大部分)很好。 有人知道调用是否真的有必要,还有什么可能导致我上面提到的错误吗? 下

  • 问题内容: 我们的团队正在使用SecureRandom生成密钥对列表(将SecureRandom传递给KeyPairGenerator)。对于以下两种选择中的哪一种,我们无法达成共识: 每次需要生成密钥对时都创建一个新实例 初始化静态实例并将其用于所有密钥对 通常哪种方法更好, 为什么 ? 添加:我的直觉是第二种选择更安全。但我唯一的论点是基于以下假设的理论攻击:假随机性是从当前时间戳派生的:某人

  • 问题内容: 我需要转义[在SQL Server的sql查询中 实际上,我实际上是在寻找[[,但我不希望它像通配符一样起作用。我试过了 : 但是从这里得到错误信息: 消息102,级别15,状态1,行1“某物”附近的语法不正确。消息105,级别15,状态1,行1字符串’后的右引号; 问题答案: 使用: 您也可以使用: 在MSDN上的LIKE(Transact-SQL)中描述。

  • 我有这样的代码: 当我们没有任何其他getInstance的静态方法时,是否初始化了此单例惰性?据我所知,类只在某些情况下初始化,比如: 类的实例是使用new()关键字或使用类的反射创建的。forName(),它可能在Java中引发ClassNotFoundException (Surce:http://javarevisited.blogspot.com/2012/07/when-class-l

  • 我仍然被那些为了支持移动和转发而发明的规则弄糊涂了。有一件事我还不太确定: 转发引用是否只是rvalue引用(应用了引用折叠规则)? 如果它是一个rvalue引用,那么为什么函数: 不仅接受rvalues,还接受lvalues?