std::array::at()
accepts an argument of size_type
which usually is defined in terms of some unsinged
type e.g. std::size_t
/ unsigned long
.
The actual argument -2
is of signed int
type which is implicitly converted to size_type
while passing to at()
and becomes a valid size_type
number; but, only a wrapped-around one. See example.
By default, you don't get a compiler warning/error for implicit conversion. You have to look for your compiler options like GCC's -Wconversion
, Wsign-conversion
, etc. to enable these settings. In your case on GCC, -Wsign-conversion
will warn you about these conversions; and, in combination with -Werror
, these warnings will become errors.
Observe the compiler output of your code with compiler flags -std=c++11 -Werror -Wsign-conversion
(live):
Compiler output:
<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
Here's another example that simulates the same thing.
And, in at()
, the passed argument is validated against the array size. Here, you will get a runtime exception of type std::out_of_range as described by the documentation:
If pos
is not within the range of the container, an exception of type std::out_of_range
is thrown.
You may look at its implementation provided by your compiler if you're so inclined to.
And, when you use an invalid index with subscript operator []
e.g. a[-2]
where -2
to size_type
conversion returns into a wrapped-around value, the result will be an out-of-bounds access and will cause an Undefined Behavior.
Hope this explanation helps!