Such method is called operator[]. I understand you want that name for the checked version, but that is not the case for historical reasons (for which I'm glad).
And again, where check is needed, I will have it written myself and the way I want it (which may not involve throwing an exception). Where I don't have it written, I don't want it, at all, and I'm responsible for the consequences. I would prefer if such use pattern didn't require me jumping through hoops. Well in a better world you'd use .at(i) instead of [i] because YOU know what you are doing. Beginners don't. Advanced people neither, as can be seen by CVEs. It is not. It doesn't make your code correct, it doesn't make it work, it doesn't help you fixing the issue. It only prevents your code from crashing, which is a bad thing (because a crash - with a backtrace - is better). You keep assuming that an OOB access leads to a crash. This is NOT the case. An OOB access is UB and a security risk. Thing is, you can't prepare a meaningful error in main(). You don't have a backtrace at that point and you don't know which of the thousands of at() calls threw. Sure, your application won't crash via signal, but, as I said, that is a bad thing. I thought at least on Windows you got unhandled_exception_filter or so. Well then don't use an exception but a signal or std::abort. Or a stack-trace enhanced exception (e.g. https://sourceforge.net/p/stacktrace), still not perfect of course. Anyway at least debuggers can break on exceptions, so you got that. I don't want that marginal performance drop, especially given that I get nothing in return. Again: You get security. At least std::abort, but never continue! You could terminate the connection and things like that, but ultimately that exception doesn't help you fixing the problem. When connections are dropping like flies on your production server and you have no idea where to fix the problem, I'd prefer to get just one backtrace of a crash instead and then fix the bug in a matter of minutes. Attach a debugger, break on throw. Alternative: Have users craft packets to force a buffer-overflow and read your secrets or take over your machine. Great! With asserts enabled you'll get a crash at the point of error. Hopefully, you'll discover the bug soon enough during testing. But even in release builds, when asserts are disabled, chances are high the crash will still point you to the problematic code. Of course, memory access bugs are nasty and painful to deal with, but I honestly didn't have to deal with one for quite a long time now, even though I've never used at(). You're more likely to mess up memory when working with raw pointers. Sure, then have asserts in release mode. Optimized away in 90% of the cases but rest assured that no-one takes over your machine. I don't care if exceptions are used, anything preventing execution of the next instruction is fine.