首页 > 解决方案 > 是否在非数组指针的末尾创建一个指针,该指针不是从 C++17 中的一元运算符和未定义行为派生的?

问题描述

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

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

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

此引用包含一个非规范性脚注:

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

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

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

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

这似乎表明:

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

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

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

标签: c++arrayspointerslanguage-lawyerc++17

解决方案


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

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 祝福过,并且不是一个元素的数组。

它被修复为中的一个缺陷


推荐阅读