长话短说

给出以下代码:

int* ptr;
*ptr = 0;

*ptr 需要一个 左值到右值 的转换 ptr 在应用间接之前?

该标准涵盖的主题 左值到右值 在很多地方,但似乎没有指定足够的信息来确定是否 * 操作员 需要这样的转换。

细节

左值到右值 转换涵盖在 N3485 在部分 4.1 左值到右值的转换 段落 1 并说 (强调我的前进):

非功能,非阵列T型t的glvalue(3.10)可以转换为prvalue.53如果t是不完整的类型,则必须将这种转换不正确的程序。如果glvalue引用的对象不是T型的对象,也不是从T派生的类型的对象 或者如果对象是非初始化的,则需要此转换的程序具有不确定的行为.[...]

也是如此 *ptr = 0; 需要进行此转换?

如果我们转到部分 4 段落 1 它说:

[...]标准转换序列将应用于表达式 如果需要的话 将其转换为所需的目标类型。

那么什么时候 必要的?如果我们看一下部分 5 表达式左值到右值 段落中提到了转换 9 其中说:

每当glvalue表达式作为操作员的操作数时,期望该操作数的prvalue,lvalue-to-rvalue(4.1),阵列到阵列(4.2)或函数对二极管(4.3)标准转换为应用于将表达式转换为prvalue。[...]

和段落 11 其中说:

在某些情况下,表达式仅因其副作用而出现。这样的表达称为丢弃值表达式。[...]当且仅当表达式是挥发性质量类型的LVALUE时,应用了LVALUE-to-falue转换(4.1),这是以下[ ...]

这两个段落似乎都不适用于此代码示例并且 5.3.1 一元运算符 段落 1 它说:

一元 * 运算符执行间接寻址:所应用的表达式应为指向对象类型的指针,或指向函数类型的指针,结果是lvalue,指的是表达式指向的对象或函数。如果表达式的类型为“指向t”,则结果的类型为“ T”。 [ 笔记:通过指向不完整类型的指针(CV void除外)的间接方向是有效的。因此获得的lvalue可以以有限的方式使用(例如,以初始化参考初始化);不得将此lvalue转换为序言,请参见4.1。——尾注]

它似乎不需要 价值 的指针,我没有看到任何指针转换的要求,我是否遗漏了一些东西?

我们为什么关心?

我在其他问题中看到了一个答案和评论,声称使用未初始化的指针是未定义的行为,因为需要 左值到右值 的转换 ptr 在应用间接之前。例如: C++ 标准到底在哪里说取消引用未初始化的指针是未定义的行为? 提出这个论点,但我无法将该论点与该标准的任何最新草案版本中的内容相一致。由于我已经多次看到此内容,因此我想得到澄清。

未定义行为的实际证明并不那么重要,因为正如我在上面的链接问题中指出的那样,我们还有其他方法来实现未定义行为。

有帮助吗?

解决方案 2

我已将问题中的更新部分转换为答案,因为此时它似乎是答案,尽管我的问题无法回答,但它并不令人满意:

迪普 向我指出了两个涵盖非常相似领域的相关主题:

共识似乎是标准是 不明确的 因此无法提供我正在寻找的答案, 约瑟夫·曼斯菲尔德 发布了关于缺乏规范的缺陷报告, ,而且看起来仍然是 打开 并且不清楚什么时候可以澄清。

对于这个问题,有一些常识性的论据需要提出: 意图 标准的。一个人可以争论 从逻辑上讲,如果操作需要使用该操作数的值,则该操作数是纯右值. 。另一个论点是,如果我们回顾过去 C99标准草案默认情况下会进行左值到右值的转换 并注明了例外情况。C99 标准草案的相关部分是 6.3.2.1 左值、数组和函数指示符 段落 2 其中说:

除非它是 sizeof 运算符、一元 & 运算符、++ 运算符、-- 运算符或 的左操作数的操作数。运算符或分配操作员,没有数组类型的LVALUE转换为存储在指定对象中的值(并且不再是lvalue)。[…]

除了一些例外,它基本上表示一个操作数 转换为存储的值 自从 间接 如果这被澄清为也是如此,那么也不例外 C++ 那么它确实可以回答我的问题 是的.

正如我试图澄清未定义行为的证明并不比澄清是否强制执行左值到右值转换更重要。如果我们想证明未定义的行为,我们有其他方法。杰瑞的方法是一种常识性的方法 间接 要求表达式是指向对象或函数的指针,并且不确定的值只会偶然指向有效对象。 一般来说,C++ 标准草案并没有明确声明使用不确定值是未定义的,这与 C99 标准草案不同 在 C++11 及之后的标准中,标准没有给出明确的声明来说明使用不确定值是未定义的。例外是迭代器和扩展指针,我们确实有这样的概念 奇异值 我们在章节中被告知 24.2.1 那:

[…][ 例子:在声明未初始化的指针 x(与 int* x; 一样)之后,必须始终假定 x 具有指针的奇异值。—示例结束] [...] 可解引用的值始终是非奇异的。

和:

无效迭代器是可以是单数的迭代器。268

脚注 268 说:

该定义适用于指针,因为指针是迭代器。取消引用已失效的迭代器的效果是未定义的。

在 C++1y 中 语言发生了变化,我们确实有一个明确的声明,使用未定义的中间值,但有一些狭窄的例外.

其他提示

可以这么说,我认为你是从一个相当倾斜的角度来处理这个问题的。根据§5.3.1/1:

一元 * 操作员执行 间接: :所应用的表达式应为指向对象类型的指针,或指向函数类型的指针,结果是lvalue,指的是表达式指向的对象或函数。如果表达式的类型是“指向 T 的指针”,则结果的类型是“T”。

虽然这没有讨论左值到右值的转换,但它要求表达式是指向对象或函数的指针。未初始化的指针不会(除非,也许是偶然的)任何这样的事情,因此尝试解除引用会产生未定义的行为。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top