为什么即使使用constexpr索引,编译器也允许越界数组访问?

AnA*_*ons 10 c++ arrays constexpr c++14 c++17

例如,如果我们有一个std::array并且我们使用constexpr编译器实例化一个超出绑定的元素将不会报告错误:

constexpr int EvaluateSpecialArrayIndex(int a)
{ return a * sizeof(int); }

array<int, 5> arr;

cout << arr[98] << endl; //compiles fine

cout << arr[EvaluateSpecialArrayIndex(4)] << endl; //the same as above
Run Code Online (Sandbox Code Playgroud)

我们不能以某种方式限制这个吗?

How*_*ant 13

要确保constexpr在编译时评估函数,必须通过生成结果强制它们constexpr.例如:

#include <array>

int
main()
{
    constexpr std::array<int, 5> arr{1, 2, 3, 4, 5};
    int i = arr[6];  // run time error
}
Run Code Online (Sandbox Code Playgroud)

然而:

#include <array>

int
main()
{
    constexpr std::array<int, 5> arr{1, 2, 3, 4, 5};
    constexpr int i = arr[6];  // compile time error
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,为了实际工作,std::array必须符合C++ 14规范,而不是C++ 11规范.由于C++ 11规范没有标记with 的const重载.std::array::operator[]constexpr

所以在C++ 11中你运气不好.在C++ 14中,您可以使它工作,但array前提是同时声明了调用索引运算符的结果和结果constexpr.

澄清

用于数组索引的C++ 11规范读取:

                reference operator[](size_type n);
          const_reference operator[](size_type n) const;
Run Code Online (Sandbox Code Playgroud)

并且用于数组索引的C++ 14规范读取:

                reference operator[](size_type n);
constexpr const_reference operator[](size_type n) const;
Run Code Online (Sandbox Code Playgroud)

constexpr加入到const过载用于C++ 14.

更新

并且用于数组索引的C++ 17规范读取:

constexpr       reference operator[](size_type n);
constexpr const_reference operator[](size_type n) const;
Run Code Online (Sandbox Code Playgroud)

周期现已完成.可以在编译时计算Universe.;-)

  • 没有`const`的`constexpr`的含义从C++ 11改为14. (3认同)

Rya*_*ing 7

如果您在编译时知道数组索引,则可以使用std::get索引,如果超出范围,导致编译失败

std::array<int, 4> a{{1,2,3,4}};
std::get<4>(a); // out of bounds, fails to compile
Run Code Online (Sandbox Code Playgroud)

我从gcc-4.9得到的错误以:

error: static assertion failed: index is out of bounds
       static_assert(_Int < _Nm, "index is out of bounds");
Run Code Online (Sandbox Code Playgroud)

std::get仅适用于常量表达式索引(索引是模板参数),因此使用std::array它始终可以在编译时检测越界.


0x4*_*2D2 6

std::array对于常规C数组,a 上的数组访问是相同的,它从不检查索引是否有效,如果它超出范围,它只调用UB.如果需要限制,请使用为超出数组边界的值std::array::at()抛出std::out_of_range()异常.

arr.at(EvaluateSpecialArrayIndex(4)); // terminate called after throwing
                                      // an instance of 'std::out_of_range'
Run Code Online (Sandbox Code Playgroud)

如果您想要编译时错误,请使用std::get:

std::get<EvaluateSpecialArrayIndex(4)>(arr); // error: static_assert failed
                                             // "index is out of bounds"
Run Code Online (Sandbox Code Playgroud)