Note that std::vector's at() predates C++11, whereas std::span was added in C++20. It's a myth that C++ is getting more memory-safe; in many aspects it's actually regressing.
Note that std::vector's at() predates C++11, whereas std::span was added in C++20. It's a myth that C++ is getting more memory-safe; in many aspects it's actually regressing.
In a greenfield project where you control every line of C++ code, you can easily achieve very good safety using nothing but ancient C++ features.
Not just memory safety. I mean, you can make your own numeric types that do overflow checks and throw exceptions or whatever. It probably won't be very fast, but it will be solid.
People have used C++ (ancient C++) to make numeric types with units, where you can't add "kilograms per second" to "meters". I remember that from some talk thing I went to in 1999.
All three major C++ standard library implementations have an option to enable assertion checks in both std::vector and std::span operator[]. Enable them unless you are in such a resource limited environment that you can't afford the checks (unlikely). The only reason the standard doesn't require the checks is to allow C++ to be usable in those resource limited environments. You could argue the checks should be enabled by default, but that's not something for the standard to decide, complain to your standard library vendor.