std:array indexing and operator[]

132 views Asked by At

Why does operator [] work here?

int main()
{
    std::array<std::size_t, 10> a;

    // Example with C++23 size_t literal

    for (auto i = 0uz; i != a.size(); ++i)
        std::cout << (a[i] = i) << ' ';

    std::cout << '\n';

    // Example of decrementing loop

    for (std::size_t i = a.size() ; i--;)
        std::cout << a[i] << ' ';

    std::cout << '\n';
}

I’m referring to these 2 lines in the decrementing loop:

for (std::size_t i = a.size() ; i--;)
    std::cout << a[i] << ' ';

As I checked, a.size() returns i=10, but then a[i] is chalked up as 9 instead of 10, so a[9] is fine while a[10] obviously would not.

So, is std::array "fixing" i via the operator[] index here, under the radar? Otherwise, as far as I tried to edit the code, I can’t see how it comes together.

I made variables for the i and a[i] values and altered the for loop, but it didn't help me understand.

2

There are 2 answers

2
Remy Lebeau On

So, is std::array "fixing" i via the operator[] index here, under the radar?

No. array::operator[] uses the index it is given, and specifying an index out of bounds is Undefined Behavior as the operator does not perform any bounds checking.

The "fix" is being done in the 2nd loop itself, before it calls the operator[].

In the 1st loop, i starts at 0 and is incremented after being passed to a[]. The loop is doing the equivalent of this:

auto i = 0uz;
while (i != a.size()) {
    a[i] = i;
    std::cout << a[i] << ' ';
    ++i;
}

On the first iteration, i is 0, and on the last iteration i is 9. So, the 1st loop is accessing array elements at indexes 0..9.

In the 2nd loop, i starts at 10 and is decremented before being passed to a[]. The loop is doing the equivalent of this:

std::size_t i = a.size(), tmp;
do {
    tmp = i;
    --i;
    if (tmp == 0) break;
    std::cout << a[i] << ' ';
}
while (true);

On the first iteration, i is 10 and then decremented to 9, and on the last iteration i is 1 and decremented to 0 (the next iteration breaks the loop without accessing the array). So, the 2nd loop is accessing array elements at indexes 9..0.

1
Chris On

Remy Lebeau has nicely answered the question as asked, but also note that you can use reverse iterators to avoid this issue entirely when iterating over a collection in reverse.

int main()
{
    std::array<std::size_t, 10> a;

    // Example with C++23 size_t literal

    for (auto i = 0uz; i != a.size(); ++i)
        std::cout << (a[i] = i) << ' ';

    std::cout << '\n';

    // Example of decrementing loop

    for (auto itr = a.rbegin(); itr != a.rend(); itr++)
        std::cout << *itr << ' ';

    std::cout << '\n';
}