8

我试图在 Microsoft Visual Studio 中创建一些示例代码,看起来像这样

int main()
{
    const size_t size = 10;
    int arr[size];

    for (size_t i = 0; i < size; ++i)
        arr[i] = i;

    return 0;
}

现在 JetBrains ResharperC++ 发出以下警告arr[i] = i;

在此处输入图像描述 当索引不是整数常量表达式时,不要使用数组下标;改用 gsl::at()

我无法理解我的意思以及如何解决此警告。

由于这是我经常使用的方案,我有点担心这个警告。

任何人都可以建议或指出我正确的方向吗?

编辑:将循环更改为:

for (size_t i = 0; i < size; ++i)
    arr[i] = 0;

仍然产生警告。

4

8 回答 8

3

arr[i]它是一个不进行任何边界检查的警告,您应该gsl::at(arr, i)https://github.com/Microsoft/GSL使用它,因为它会进行边界检查并且更安全。

于 2018-08-17T12:51:57.907 回答
3

一般来说

for (size_t i = 0; i < size; ++i)
    arr[i] = something;

很危险。您无法判断是否arr[i]会超出数组范围。这就是为什么C++ 核心指南建议您使用gsl::at()它,因为它会进行边界检查以确保您不会超出数组的边界。

不过,这不是唯一的解决方案。如果您只需要在范围上进行迭代,则可以使用基于范围的 for 循环,例如

for (const auto& e : arr)
    //e is each element of the array and is not mutable here

或者

for (auto& e : arr)
    //e is each element of the array and is mutable here

对于像您这样需要填充数组的情况,您可以std::iota使用

std::iota(std::begin(arr), std::end(arr), 0);

并且所有这些都保证不会越界。

于 2018-08-17T13:15:34.923 回答
1

这不是(编译器)警告。它是纳入第 3 方 IDE/分析工具的C++ 核心指南之一。

于 2018-08-17T13:02:48.267 回答
1

我认为警告的原因是operator[]没有边界检查,虽然gsl::at()可以。

由于size在编译时已知,如果索引是constexpr,您可能会收到警告,但如果该值是在运行时确定的,则不能。在我看来完全没有必要。

于 2018-08-17T12:51:44.743 回答
1

通过索引访问数组元素,而不进行任何边界检查,不被认为是一种好的做法。这是一种不安全的直接内存访问,可能会导致分段错误

对于像 一样的 STL 容器std::vector,有这个at()成员函数执行边界检查,并且是访问元素的推荐方式。

对于这个简单的示例,您可以忽略此警告。但是,对于重要的代码,请使用std::vector. 但是,对于 C 风格的数组,您也可以下载并使用gsl::at()和探索它的其他工具。


参考资料:
C++ 核心指南
GSL(指南支持库)

于 2018-08-17T12:57:06.073 回答
0

int array[] = {0, 1, 2};
for (auto element : array){
   if(element == 1){
   //.....
   }
}

试试上面的代码。

于 2020-11-10T09:34:50.263 回答
0

这是一个警告,因为operator[]它不检查绑定,与at. 而在您的情况下,代码是正确的,“小”更改可能会破坏您的循环(int arr[2 * size];

在您的情况下,有几种使用迭代器(显式或隐式)的好选择:

const size_t size = 10;
int arr[size];

std::iota(std::begin(arr), std::end(arr), 0);

或者

int i = 0;
for (auto& e : arr) {
    e = i;
    ++i;
}
于 2018-08-17T13:34:56.787 回答
0

这似乎需要一个更新的答案。

建议使用标准的 alogos,而不是使用手写循环。在这种情况下iota,正是需要的:自动递增分配。

对于静态数组,我们也应该使用 std::array 而不是 'C' 样式的数组。但这对向量也适用,因为 iota 需要运行时参数。

template<size_t SZ>
auto<int, SZ> CountInit()
{
    std::array<int, SZ> arr; // Note we only use SZ once

    std::iota(arr.begin(), arr.end(), 0);
    return arr;
}

这可以使用 integer_sequence 和一些帮助程序以更多的编译时间方式完成:

// Note taken from : https://jgreitemann.github.io/2018/09/15/variadic-expansion-in-aggregate-initialization/
template <typename Container, int... I>
Container iota_impl(std::integer_sequence<int, I...>) {
    return {I...};
} 

template <typename T, std::size_t N>
auto iota_array() {
    using Sequence = std::make_integer_sequence<int, N>;
    return iota_impl<std::array<T, N>>(Sequence{});
}



auto foo2()
{
    return iota_array<int, 10>();
}

int goo2()
{
    auto x=foo2();
    return std::accumulate(x.begin(), x.end(), 0);
}

根据https://godbolt.org/z/59hqqdEYj这些是等价的(根据 c++20 iota 是 constexpr)

于 2021-09-27T00:24:28.537 回答