【问题标题】:Is creating a pointer one past the end of a non-array pointer not derived from unary operator & undefined behavior in C++17?是否在非数组指针的末尾创建一个指针,该指针不是从 C++17 中的一元运算符和未定义行为派生的?
【发布时间】:2018-06-18 18:40:42
【问题描述】:

C++17 标准似乎说,如果指针指向数组元素,则只能将整数添加到指针,或者,作为特殊例外,指针是一元运算符 & 的结果:

8.5.6 [expr.add] 描述对指针的加法:

当一个整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。如果表达式 P 指向具有 n 个元素的数组对象的元素 x[i] x,则表达式 P + J 和 J + P(其中 J 的值为 j)指向(可能-假设的)元素 x[i + j] 如果 0 ≤ i + j ≤ n; 否则,行为未定义

此引用包含non-normative 脚注:

为了这个目的,一个不是数组元素的对象被认为属于一个单元素数组; 见 8.5.2.1

引用 8.5.2.1 [expr.unary.op] 讨论一元 & 运算符:

一元 & 运算符的结果 是一个指向其操作数的指针...对于指针算术 (8.5.6) 和比较 (8.5.9, 8.5.10),一个对象不是数组元素其地址是以这种方式获取的被认为属于具有一个 T 类型元素的数组。

非规范脚注似乎有点误导,因为它引用的部分描述了特定于一元运算符 & 的结果的行为。似乎没有任何东西允许将其他指针(例如来自非数组 new)视为单元素数组。

这似乎表明:

void f(int a) {
    int* z = (new int) + 1; // undefined behavior
    int* w = &a + 1; // ok
}

这是对 C++17 所做更改的疏忽吗?我错过了什么吗?是否有理由只为一元运算符&提供“单元素数组规则”?

注意:如标题中所述,此问题特定于 C++17。 C 标准和 C++ 标准的早期版本包含不再存在的清晰规范语言。像 this 这样较老的模糊问题不相关。

【问题讨论】:

  • "非规范脚注似乎有点误导" 这就是非规范符号的用途。他们用简单的英语解释了一些在别处更明确地详细说明的东西。 “是否有理由只为一元运算符 & 提供“单元素数组规则”?” 是否有理由为其他东西提供它?
  • @NicolBolas 如果您使用new 分配单个对象,您仍然有一个指向单个对象的指针而不使用&,正如OP 所述。问题是这条规则是否也适用于这种情况(或相关情况)。
  • 对我来说似乎是一个疏忽,因为 p==&*p 的定义。
  • 嗯,我个人将 8.5.2.1 解释为:如果我们这样取地址,那么我们有......没有提到对于 else 明确表示,所以状态还 open。 8.5.6 概括了脚注中的问题,将单元素数组规则扩展到 else 情况。规范扩展——见@n.m。的评论...

标签: c++ arrays pointers language-lawyer c++17


【解决方案1】:

是的,这似乎是 标准中的一个错误。

int* z = (new int)+1; // undefined behavior.
int* a = new int;
int* b = a+1; // undefined behavior, same reason as `z`
&*a; // seeming noop, but magically makes `*a` into an array of one element!
int* c = a+1; // defined behavior!

这太荒谬了。

8.5.2.1 [expr.unary.op]

[...] 以这种方式获取地址的不是数组元素的对象被认为属于具有一个 T 类型元素的数组

一旦被 8.5.2.1 “祝福”,对象就是一个元素的数组。如果您没有通过至少一次调用& 来祝福它,那么它从未被 8.5.2.1 祝福过,并且不是一个元素的数组。

它在 中被修复为defect

【讨论】:

  • 每个 C 或 C++ 标准都遵循 C89 的传统,即期望编译器编写者认识到,如果标准的某些部分定义了某些动作类别的行为,则其他部分表示重叠的一般类别动作调用 UB,当没有合理的理由不这样做时,应以定义的方式处理属于这两种类别的动作。认识到这一点的编译器编写者不需要通过排除所有豁免来使第二类规范复杂化,而那些不需要标准的编译器编写者不太可能......
  • ...即使标准排除了所有需要的豁免,也能生成高质量的编译器。如果这些标准被解释为设计的那样,那么标准未能从识别一般 UB 类别的规则中排除每一项豁免将不是缺陷。
猜你喜欢
  • 2020-04-29
  • 1970-01-01
  • 2018-01-02
  • 1970-01-01
  • 2019-04-06
  • 2019-12-28
  • 2017-04-12
  • 1970-01-01
  • 2011-04-24
相关资源
最近更新 更多