简体   繁体   English

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

[英]Why does compiler allow out-of-bounds array access even with constexpr index?

For example if we have an std::array and we instantiate an element that is out of bound using constexpr the compiler wouldn't report error: 例如,如果我们有一个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

Can't we restrict this somehow? 我们不能以某种方式限制这个吗?

To ensure that constexpr functions are evaluated at compile time, you must force them to be by making their result constexpr . 要确保在编译时评估constexpr函数,必须通过使其结果为constexpr来强制它们。 For example: 例如:

#include <array>

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

However: 然而:

#include <array>

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

Unfortunately, for this to actually work, std::array must conform to the C++14 specification, not the C++11 specification. 不幸的是,为了实际工作, std::array必须符合C ++ 14规范,而不是C ++ 11规范。 As the C++11 specification does not mark the const overload of std::array::operator[] with constexpr . 由于C ++ 11规范没有使用constexpr标记std::array::operator[]const重载。

So in C++11 you're out of luck. 所以在C ++ 11中你运气不好。 In C++14, you can make it work, but only if both the array and the result of calling the index operator are declared constexpr . 在C ++ 14中,您可以使它工作,但constexprarray和调用索引运算符的结果都声明为constexpr

Clarification 澄清

The C++11 specification for array indexing reads: 用于数组索引的C ++ 11规范读取:

                reference operator[](size_type n);
          const_reference operator[](size_type n) const;

And the C++14 specification for array indexing reads: 并且用于数组索引的C ++ 14规范读取:

                reference operator[](size_type n);
constexpr const_reference operator[](size_type n) const;

Ie constexpr was added to the const overload for C++14. constexpr被添加到C ++ 14的const重载中。

Update 更新

And the C++17 specification for array indexing reads: 并且用于数组索引的C ++ 17规范读取:

constexpr       reference operator[](size_type n);
constexpr const_reference operator[](size_type n) const;

The cycle is now complete. 周期现已完成。 The universe can be computed at compile-time. 可以在编译时计算Universe。 ;-) ;-)

If you know the array index at compile time, you could use std::get with an index, and that will cause a compilation failure if you're out of bounds 如果您在编译时知道数组索引,则可以将std::get与索引一起使用,如果超出范围, 导致编译失败

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

The error I get from gcc-4.9 ends with: 我从gcc-4.9得到的错误以:

error: static assertion failed: index is out of bounds
       static_assert(_Int < _Nm, "index is out of bounds");

std::get only works with constant expression indices (the index is a template argument), so with std::array it can always detect out-of-bounds at compile time. std::get仅适用于常量表达式索引(索引是模板参数),因此对于std::array它始终可以在编译时检测出越界。

Array access on an std::array is the same for a regular C-array, it never checks to see if the index is valid, it just invokes UB if it's out of range. 对于常规C数组, std::array上的数组访问是相同的,它从不检查索引是否有效,如果它超出范围,它只调用UB。 If you want restrictions, use std::array::at() which throws an std::out_of_range() exception for values that exceed the array bounds. 如果需要限制,请使用std::array::at() ,它会为超出数组边界的值抛出std::out_of_range()异常。

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

If you want a compile-time error use std::get : 如果你想要编译时错误,请使用std::get

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

Simple answer, because it would be very costly for std::array to have separate constexpr overloads to check for this sort of thing. 简单的回答,因为std::array具有单独的constexpr重载来检查这种事情是非常昂贵的。 If you want, you can write your own wrapper around std::array that offers a compile-checked access for compile time constants. 如果需要,可以在std::array周围编写自己的包装器,为编译时常量提供编译检查访问。 Something like: 就像是:

template<typename T, size_t S>
class safeArray
{
    std::array<T, S> m_arr;
    public:
    template<size_t A>
    T& safeAt() { 
        static_assert(A < S, "Index out of bounds");
        return m_arr[A]; 
    }
    // other funcs as needed
};

Then, you can do something like: 然后,您可以执行以下操作:

safeArray<int, 5> arr;
cout << arr.safeAt<98>() << endl; // compile error

This can generate a lot of functions, however. 然而,这可以产生许多功能。 Most of the time, if your design is sound, you won't ever need this type of check. 大多数情况下,如果您的设计合理,您将不需要这种类型的检查。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么Cppcheck没有找到这个明显的数组越界错误? - Why does Cppcheck not find this obvious array out-of-bounds error? 为什么 constexpr 不会导致编译在索引越界时失败 - Why does constexpr not cause compilation to fail on index out of bounds 为什么 C++ 不允许访问 constexpr 数组的地址 - Why C++ does not allow access address of a constexpr array 跟踪iPhone上的出站访问 - Track down out-of-bounds access on iPhone 为什么越界指针算术未定义的行为? - Why is out-of-bounds pointer arithmetic undefined behaviour? 如何创建一个让用户知道自己越界的数组? - How to create a array that lets user know they are out-of-bounds? 为什么MSVC编译器不检测std :: array越界访问 - Why MSVC compiler does not detect std::array out of bound access 为什么CppCheck为这个静态const数组提供了一个数组访问超出范围的错误? - Why does CppCheck give an array access out of bounds error for this static const array? 为什么编译器会抱怨对constexpr函数的未定义引用,即使它是在另一个源文件中定义的? - Why does the compiler complain about undefined reference to a constexpr function even though it is defined in another source file? 为什么编译器抱怨这不是constexpr? - Why does the compiler complain about this not being a constexpr?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM