If you use ".end()" on an C++ standard array collection, what you get is not the array size. You get an invalid iterator pointing one element past the end of the array, which tells you when to stop.
Most newer languages have built-in syntax for "iterate over collection". C++ does not, leading to somewhat clunky constructs like this. It's ugly, but that's where C++ ended up.
(I personally think that the C++ committee went way too far in making the template fanatics happy. It's neat that C++ templates, being a general term-rewriting system, allow arbitrary computation at compile time, but templates are a terrible programming language. More recently, it worries me that Rust is going too far in that direction.)