【问题标题】:an out of range pointer to array is forbidden with constexprconstexpr 禁止使用超出范围的数组指针
【发布时间】:2020-09-23 12:19:03
【问题描述】:

我正在使用 constexpr 方法实现一个 Array 类。在我的设计中,我允许迭代器超过 end(),因为我没有做:while (it != arr.end()),而是通过在内部比较两个原始指针来做:while (arr.finished(it)) .它适用于非 constexpr 数组实例,但不适用于 constexpr 实例,因为以下问题:

#include <array>

int main()
{
    static constexpr std::array<int, 3> arr{};

    constexpr const int* ptr = &arr[0];

    constexpr const int* ptr2 = (const int*)ptr + 4;// error

    return 0;
}

我收到了消息:

array subscript value 4 is outside the bounds of array type _Type {aka const int [3]}|

https://godbolt.org/z/MjbqEv

Windows 10 和 gcc10.1.0 位于 C:\cygwin64\usr\local\bin

我什至没有取消引用指针,所以我对编译器的“小心”感到愤怒。

我的问题是:

我可以做些什么来编译这段代码并保持我的设计选择有越界迭代器? (不仅仅是编译器已经允许的最后一个结尾)。我可以用 gcc 禁用越界错误吗?

【问题讨论】:

  • 当你使用constexpr时,编译器有义务检查UB。它不能忽视它。由于数组边界外的指针算术是UB,编译器必须报错。
  • 超出end() 是标准的UB。
  • constexpr 能够检测 UB 并将它们作为错误线程。所以你的代码有 UB 应该被修复。
  • @Evg 感谢 cmets,有什么原因吗?
  • @Cevik 看看this answer一些架构有专门的寄存器来保存指针。将未映射地址的值放入这样的寄存器是允许崩溃的。

标签: c++ arrays pointers constexpr


【解决方案1】:

我什至没有取消引用指针,所以我对编译器的“小心”感到愤怒。

您观察到的并不是一个过于谨慎的编译器。不允许将指针递增超过数组的最后一个元素。你不需要取消引用指针就会有麻烦。

您只能将指针递增到最后一个元素之后的位置(并且您不能取消引用该最后一个元素的指针)。

在非常量表达式上下文中递增ptr + 4 将是未定义的行为。然而,在编译期间,没有未定义的行为,编译器会诊断问题。

【讨论】:

    【解决方案2】:

    您不能在 C++ 中执行超出数组边界的指针运算。这种操作的行为是未定义的。并且在不断求值的表达式中具有未定义行为的程序是格式错误的,因此允许编译器拒绝编译它(并且需要对其进行诊断)。

    您无法使用指针来实现这一点,但您可以实现一个自定义迭代器类来与您的自定义 Array 类一起使用。

    【讨论】:

    • 感谢您的回答。我确实实现了这样一个迭代器类,但我无法想象如果我存储一个指针和一个偏移量而不是一个指针会有什么表现!
    • 你的意思是我可以在我的迭代器的编译时版本中存储对数组的引用,因为它是编译时的?我认为这实际上是个好主意!谢谢。但我还需要根据上下文消除使用哪个实现的歧义。嗯,我认为 is_constant_call 或标准中有一些东西......
    • @Cevik 没关系,您确实需要迭代器的指针。仅包含偏移量的东西可以与数组的成员函数一起使用,这是我出于某种原因想到的。它不能用作通用迭代器。
    猜你喜欢
    • 2011-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-09
    • 1970-01-01
    • 1970-01-01
    • 2018-07-04
    • 1970-01-01
    相关资源
    最近更新 更多