【发布时间】:2014-01-29 22:55:00
【问题描述】:
TL;DR
给定以下代码:
int* ptr;
*ptr = 0;
*ptr 是否需要在应用间接之前对ptr 进行左值到右值转换?
该标准在很多地方都涵盖了 lvalue-to-rvalue 的主题,但似乎没有指定足够的信息来确定 * 运算符 是否需要这样的转换。
详情
左值到右值的转换在N3485部分4.1中介绍左值到右值转换段落1并说(强调我的未来):
可以转换非函数、非数组类型 T 的泛左值 (3.10) 到一个prvalue.53如果T是一个不完整的类型,一个程序 需要这种转换是不正确的。如果对象 左值引用不是 T 类型的对象,也不是 a 的对象 从 T 派生的类型,或者如果对象未初始化,则为程序 必须进行此转换的行为未定义。[...]
*ptr = 0;需要这种转换吗?
如果我们转到 4 段落 1 部分,它会说:
[...]标准转换序列将应用于表达式 如有必要将其转换为所需的目标类型。
那么什么时候需要?如果我们查看5 Expressions 部分,9 段中提到了 lvalue-to-rvalue 转换:
当一个泛左值表达式作为一个运算符的操作数出现时 期望该操作数的纯右值,左值到右值(4.1), 数组到指针 (4.2) 或函数到指针 (4.3) 标准 应用转换将表达式转换为纯右值。 [...]
和第11段说:
在某些情况下,表达式仅出于其副作用而出现。 这样的表达式称为丢弃值表达式。[...] 当且仅当 表达式是 volatile 限定类型的左值,它是 以下 [...]
这两个段落似乎都不适用于此代码示例,5.3.1 一元运算符段落 1 它说:
一元 * 运算符执行间接:它所指向的表达式 应用的应该是指向对象类型的指针,或指向 函数类型,结果是引用对象的左值或 表达式指向的函数。如果表达式的类型 是“指向 T 的指针”,结果的类型是“T”。 [注:间接 通过指向不完整类型(除了 cv void)的指针是有效的。 这样获得的左值可以以有限的方式使用(初始化一个 参考,例如);此左值不得转换为 prvalue,见 4.1。 ——尾注]
它似乎不需要指针的 值,而且我没有看到任何指针转换的要求,我错过了什么吗?
我们为什么要关心?
我在其他问题中看到了一个答案和 cmets,声称使用未初始化的指针是未定义的行为,因为在应用间接之前需要对 ptr 进行 lvalue-to-rvalue 转换。例如:Where exactly does C++ standard say dereferencing an uninitialized pointer is undefined behavior? 提出了这个论点,我无法将该论点与该标准的任何最新草案版本中的内容相一致。由于我已经多次看到这一点,我想得到澄清。
未定义行为的实际证明并不重要,因为正如我在上面的链接问题中指出的那样,我们还有其他方法可以解决未定义行为。
【问题讨论】:
-
“它似乎没有” 明确 “需要指针的值”。曾经可能会争辩说该值是隐式(按“常识”)要求的。
-
明确地说,您的目标是弄清楚标准的哪一部分使
int *p; *p=0;行为未定义?如果做不到这一点,发现标准中的错误? -
@Yakk 换个说法,答案影响你是否可以使用这个参数来显示使用未初始化的指针是 UB,但这不是唯一的参数,我们可以显示它是 UB b/c we must assume it is singular。我看到三个结果
1)有缺陷,标准应该明确说明存在左到右转换2)没有强制转换,这不是 UB3)左到右转换的证明是隐含的,它确实证明了 UB。 -
@dyp 但如果它是隐含的,这是否意味着对变量的任何读取都需要从左到右的转换?如果是这样,那么为什么
5部分中的所有特定语言? -
@ShafikYaghmour 我不确定是否每次读取都需要从左到右的转换。 Jerry Coffin 的解释通过违反要求给出了 UB w/o l-to-r。类似问题:stackoverflow.com/q/14991219/420683stackoverflow.com/q/14935722/420683
标签: c++ pointers language-lawyer indirection lvalue-to-rvalue