On Thu, Nov 28, 2019 at 9:52 AM Peter Dimov via Boost
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
Zach Laine wrote: 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
into a fixed_string. In both cases, we have no idea whether they'll fit or not. And yes, when they are known in advance, we can compute the final size in one loop, check, then += in a second loop, avoiding the check on each iteration. So there's a potential efficiency loss here, outweighed by gain of convenience and loss of buffer overflow exploits in the more common case where the accumulated strings come one by one from input.
Ok, I understand your point a bit better now I think. Is it the unboundedly-large nature of a NTBS that has you concerned? That is, do you think that op+=(char) should assert and op+=(char const *) should throw? That position makes sense to me, thought I don't share it -- though I think that's just taste. However, I cannot imagine why I'd ever want op+=(char) or op+=(string_view) to throw. Zach