[英]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中,您可以使它工作,但
constexpr
是array
和调用索引运算符的结果都声明为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.