书上说 std::array
比其他赋值方法更安全、更简单。
这是我的代码。
#include<iostream>
#include<array>
using namespace std;
int main()
{
array<int, 5> a = {1, 2, 3, 4, 5};
a.at(-2) = 100;
cout << a[-2] << endl;
return 0;
}
为什么这段代码中没有警告或错误?
的 at
成员函数进行运行时检查,而 operator[]
不进行检查(这是有意设计的)。
你可以通过使用 get
:
#include <array>
using namespace std;
int main()
{
array<int, 5> a = {1, 2, 3, 4, 5};
get<1>(a) = 100; // ok
get<-2>(a) = 100; // error
get<5>(a) = 100; // error
}
std::array::at()
接受一个参数: size_type
通常是根据一些 unsinged
类型 例如 std::size_t
unsigned long
.
实际参数 -2
是 signed int
属于 默化 到 size_type
同时传递给 at()
并成为有效的 size_type
数;但是,只能是一个绕口令。见 例子.
默认情况下,你不会收到隐式转换的编译器警告错误。你必须寻找你的编译器选项,如 海合会的 -Wconversion
, Wsign-conversion
等来启用这些设置。在你的情况下,在GCC上。-Wsign-conversion
会对这些转换提出警告;并且,结合着 -Werror
这些警告会变成错误。
观察编译器输出的代码,编译器的标志是 -std=c++11 -Werror -Wsign-conversion
(住):
编译器输出。
<source>: In function 'int main()':
<source>:6:10: error: unsigned conversion from 'int' to 'std::array<int, 5>::size_type' {aka 'long unsigned int'} changes value from '-2' to '18446744073709551614' [-Werror=sign-conversion]
6 | a.at(-2)=100;
| ^~
<source>:7:13: error: unsigned conversion from 'int' to 'std::array<int, 5>::size_type' {aka 'long unsigned int'} changes value from '-2' to '18446744073709551614' [-Werror=sign-conversion]
7 | cout<<a[-2]<<endl;
| ^~
cc1plus: all warnings being treated as errors
这是另一个 例子 ,模拟了同样的事情。
而且,在 at()
,通过的参数将根据数组大小进行验证。这里,你会得到一个类型为 std::out_of_range 所述 文件:
如果:
pos
不在容器的范围内,就会出现类型为std::out_of_range
被抛出。
如果你愿意的话,你可以看看你的编译器提供的实现。
而且,当你使用一个无效的索引与 下标运算符 []
例如 a[-2]
哪儿 -2
到 size_type
转换后返回一个环绕的值,结果将是一个越界访问,并将导致一个 未定义的行为.
希望这个解释能帮到你
访问无效的 std::array
含有 .at
将导致异常处理程序抛出运行时错误,无论你是在发布版还是调试版中编译和运行它。
只有当你使用成员访问操作符的时候,你才不会看到错误。[]
就像你在发布模式下的例子一样,在调试模式下,你只会在编译和运行后得到越界的错误。
cout<<a[-2]<<endl;
在调试模式下,你只有在编译和运行后才会得到越界的错误。在发布模式下,这是未定义的行为。
这也是为什么使用 .at
建议不要直接使用 []
运营商。