My colleague’s code looked like this:
void copy(std::string const& s, char *d) {
for(int i = 0; i <= s.size(); i++, d++)
*d = s[i];
}
His application crashes and I think that it is because this accesses s out of range, since the condition should go only up to s.size() - 1.
But other guys next to me says there was a discussion in the past about this being legal. Can anyone please clear this up for me?
Let’s put aside the possiblity that
*dis invalid since that has nothing to do with what the question seems directed at: whether or notstd::string operator[]()has well defined behavior when accessing the “element” at indexstd::string::size().The C++03 standard has the following description of
string::operator[]()(21.3.4 “basic_stringelement access”):Since
sin the example code isconst, the behavior is well defined ands[s.size()]will return a null character. However, ifswas not aconst string, the behavior would be undefined.C++11 remedies this odd-ball behavior of the
constversion behaving so differently than the non-const version in this edge case. C++11 21.4.5 “basic_stringelement access” says:So for a C++11 compiler, the behavior is well-defined whether or not the
stringisconst.Unrelated to the question, I find it a little strange that C++11 says that “the referenced value shall not be modified” – it’s not clear to me if that clause applies only in the case where
pos == size(). I’m pretty sure there’s a ton of existing code that does things likes[i] = some_character;wheresis a non-conststd:stringandi < s.size(). Is that undefined behavior now? I suspect that that clause applies only to the special-casecharT()object.Another interesting thing is that neither standard seems to require that the address of the object returned for
s[s.size()]be in any way related to the address of the object returned fors[s.size() - 1]. In other words, it seems like the returnedcharT()reference doesn’t have to be contiguous to the end of the string data. I suspect that this is to give implementers a choice to just return a reference to a single static copy of that sentinel element if desired (that would also explain C++11’s “shall not be modified” restriction, assuming it applies only to the special case).