I understand that arrays are a primitive class and therefore do not have built in methods to detect out of range errors. However, the vector class has the built in function .at() which does detect these errors. By using namespaces, anyone can overload the [ ] symbols to act as the .at() function by throwing an error when a value out of the vector's range is accessed. My question is this: why is this functionality not default in C++?
EDIT: Below is an example in pseudocode (I believe - correct me if needed) of overloading the vector operator [ ]:
Item_Type& operator[](size_t index) { // Verify that the index is legal.
if (index < 0 || index >= num_items) {
throw std::out_of_range
("index to operator[] is out of range");
}
return the_data[index]
}
I believe this function can be written into a user-defined namespace and is reasonably easy to implement. If this is true, why is it not default?
For something that's normally as cheap as []
, bounds checking adds a significant overhead.
Consider
int f1(const std::vector<int> & v, std:size_t s) { return v[s]; }
this function translates to just three lines of assembly:
movq (%rdi), %rax
movl (%rax,%rsi,4), %eax
ret
Now consider the bounds-checking version using at()
:
int f2(const std::vector<int> & v, std:size_t s) { return v.at(s); }
This becomes
movq (%rdi), %rax
movq 8(%rdi), %rdx
subq %rax, %rdx
sarq $2, %rdx
cmpq %rdx, %rsi
jae .L6
movl (%rax,%rsi,4), %eax
ret
.L6:
pushq %rax
movl $.LC1, %edi
xorl %eax, %eax
call std::__throw_out_of_range_fmt(char const*, ...)
Even in the normal (non-throwing) code path, that's 8 lines of assembly - almost three times as many.
C++ has a principle of only pay for what you use. Therefore unchecked operations definitely have their place; just because you're too lazy to be careful about your bounds doesn't mean I should have to pay a performance penalty.
Historically array []
has been unchecked in both C and C++. Just because languages 10-20 years younger made that a checked operation doesn't mean C++ needs to make such a fundamental backward-incompatible change.