Zach Laine wrote:
What makes op[] a user error is that the index rarely comes from external input. It typically comes from a variable that the programmer controls and program logic ensures is in range.
I disagree. What puts vector::operator+ inherently (which is directly analogous to fixed_string::operator+) more out of programmer control than vector::operator[]?
Nothing inherently makes it so. It just is, in the observable universe.
Moreover, there are two things to consider:
1) Can I use this function within a context in which I know that the precondition check/throwing condition is not needed?
This is in part an efficiency concern, of course.
Even if this only occurs 0.1% of the time, the design should cater to it because of the mere possibility? The flip side is the loss of efficiency when you do have to check. You need to compute the size of the argument twice, which in the char const* case isn't free.
2) If the check is needed, can the programmer write code that can sensibly deal with the problem?
Sure, throw an exception. :-)
Ok, then do you advocate that fixed_string::operator+=(fixed_string) have preconditions and not throw, and that fixed_string::operator+=(char const *) should throw instead?
No. I would "precondition" `op+=( char const (&)[ M ] )` (and op=) by
failing at compile time when M > N, because the size is known, but in
fixed_string's case, the size isn't known.
There's no significant difference between accumulating the elements of
vector<string> and those of vector