初始化指向数组末尾后一位的引用是否仍为未定义行为?
引用绑定到数组尾后元素的未定义行为判定
先看你提供的可在GCC、Clang、MSVC编译的代码:
consteval int foo() { int a[1]{ 42 }; int& ir = a[1]; return *(&ir-1); } int main() { constexpr int ci=foo(); return ci; }
旧标准(n4868)下的判定
在n4868(对应C++20正式版)中,标准明确规定“引用必须初始化为指向有效的对象或函数”。这段代码里把引用ir绑定到数组a的尾后元素a[1]——这个位置不存在有效对象,因此直接违反了标准要求,属于未定义行为。编译器能编译只是因为部分编译器在常量求值阶段没有严格检查这一违规点,但从标准角度来说行为是未定义的。
新标准草案(n4950)及后续的变化
n4950(C++23的最终草案)删除了上述条款,重新调整了引用绑定的规则:允许引用绑定到数组尾后指针指向的位置,前提是不对这个引用直接解引用(即不访问它绑定的“不存在的元素”)。
回到这段代码的具体操作:
- 代码并没有直接访问
ir绑定的尾后位置(没有写*ir),而是通过&ir获取到数组的尾后指针 - 对尾后指针执行
-1操作是合法的指针算术:数组的尾后指针属于该数组指针序列的合法成员,减1后会指向数组的唯一有效元素a[0] - 最后解引用这个指向有效元素的指针,完全符合标准要求
所以在n4950及正式的C++23标准中,这段代码的行为不再属于未定义行为,是完全合法的代码。
内容的提问来源于stack exchange,提问作者doug
相关产品推荐
相关产品推荐

