在应用间接时,标准是否要求对指针变量进行左值到右值的转换?

Sha*_*our 19 c++ pointers indirection language-lawyer lvalue-to-rvalue

TL; DR

给出以下代码:

int* ptr;
*ptr = 0;
Run Code Online (Sandbox Code Playgroud)

在应用间接之前,是否*ptr需要进行左值到右值的转换ptr

该标准涵盖了许多地方的左值到左值的主题,但似乎没有指定足够的信息来确定*运算符是否需要这样的转换.

细节

左值到右值的转换是覆盖在N3485的部分4.1 左值到右值转换段落1和说(重点矿山前进):

可以将非函数非数组类型T的glvalue(3.10)转换为prvalue.53如果T是不完整类型,则需要进行此转换的程序是错误的.如果glvalue引用的对象不是T类型的对象,并且不是从T派生的类型的对象,或者如果该对象未初始化,则需要此转换的程序具有未定义的行为.[...]

那么*ptr = 0; 转换需要吗?

如果我们转到41节,它说:

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

那么什么时候需要呢?如果我们看一下5 表达式,第9段中提到了左值到右值的转换,它说:

每当glvalue表达式作为操作符的操作数出现时,该操作符需要该操作数的prvalue,左值到右值(4.1),数组到指针(4.2)或函数到指针(4.3)标准转换是用于将表达式转换为prvalue.[...]

和第11段说:

在某些情况下,表达式仅出现其副作用.这样的表达式称为丢弃值表达式.[...]当且仅当表达式是volatile限定类型的左值并且它是以下之一时,才应用左值到右值转换(4.1). ...]

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

一元*运算符执行间接:它所应用的表达式应该是指向对象类型的指针,或指向函数类型的指针,结果是指向表达式指向的对象或函数的左值.如果表达式的类型是"指向T的指针",则结果的类型为"T".[注意:通过指向不完整类型(cv void除外)的指向的间接有效.由此获得的左值可以以有限的方式使用(例如,初始化参考); 这个左值不能转换为prvalue,见4.1. - 尾注]

它似乎不需要指针的,我没有看到任何转换指针的要求,我错过了什么?

我们为什么关心?

我在其他问题中看到了答案和评论,声称使用未初始化的指针是未定义的行为,因为在应用间接之前需要进行左值到右值的转换ptr.例如:C++标准在哪里确实解除引用未初始化的指针是未定义的行为?提出这个论点,我无法将该论证与该标准的任何最新草案版本中的内容相协调.自从我多次看到这个以来,我想澄清一下.

未定义行为的实际证明并不重要,因为正如我在上面的链接问题中所指出的,我们有其他方法可以获得未定义的行为.

Jer*_*fin 13

我认为你是从一个相当倾斜的角度接近这个,可以这么说.根据§5.3.1/ 1:

一元运算*符执行间接:它所应用的表达式应该是指向对象类型的指针,或指向函数类型的指针,结果是引用表达式指向的对象或函数的左值.如果表达式的类型是"指向T的指针",则结果的类型为"T".

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

  • @dyp:我不反对它更明确,但我没有看到任何合理的解释方式,因为不要求表达式引用一个对象或函数. (2认同)

Sha*_*our 4

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

\n\n

dyp向我指出了两个相关的主题,它们涵盖了非常相似的领域:

\n\n\n\n

共识似乎是该标准指定不明确,因此无法提供我正在寻找的答案,约瑟夫·曼斯菲尔德(Joseph Mansfield) 发布了关于缺乏规范的缺陷报告,并且看起来它仍然是开放的,并且不清楚什么时候可能会得到澄清。

\n\n

关于该标准的意图,需要提出一些常识性的论点。从逻辑上讲,如果操作需要使用该操作数的值,则该操作数是纯右值。另一个论点是,如果我们回顾一下C99 标准草案,就会发现默认情况下会进行左值到右值的转换,并且会注明例外情况。C99 标准草案中的相关部分是6.3.2.1 左值、数组和函数指示符2段,其中表示:

\n\n
\n

除非它是 sizeof 运算符、一元 & 运算符、++ 运算符、-- 运算符或 的左操作数的操作数。运算符或赋值运算符,\n 不具有数组类型的左值将转换为存储在指定对象中的值(并且不再是左值)。[\xe2\x80\xa6]

\n
\n\n

这基本上是说,除了一些例外情况,操作数被转换为存储的值,并且由于间接不是例外,如果这在C++中也是如此,那么它确实可以回答我的问题yes

\n\n

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

\n\n
\n

[\xe2\x80\xa6][ 示例:在声明未初始化的指针 x(与 int* x; 一样)之后,必须始终假定 x 具有指针的奇异值。\xe2\x80\x94end 示例] [\xe2\x80\xa6] 可解除引用的值始终是非奇异的。

\n
\n\n

和:

\n\n
\n

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

\n
\n\n

脚注 268 说:

\n\n
\n

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

\n
\n\n

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

\n


归档时间:

查看次数:

775 次

最近记录:

11 年 前