According to the Standard, this is not safe. The Standard goes to some considerable effort to explicitly state that writing to the NUL terminator is undefined behavior:

and

Slightly more difficult to analyze is whether &buffer[0]
points to size() + 1
consecutive characters to begin with. The Standard does not make this guarantee explicitly, and in fact the wording of operator[]
quoted above seems to leave the door open to having a buffer of only size()
consecutive characters, with the terminator stored separately. However when all the semantic rules are considered, the string must actually have room for size() + 1
characters at all times. (Otherwise a call to c_str()
, which is a const
member function, could not return a pointer to a run of size()+1
characters without invalidating references, which it is not allowed to do. A second proof, also valid, is that c_str()
cannot copy the content to a new location and still meet the complexity requirement).
However, it is not assured that the character at location size() + &buffer[0]
is actually a NUL until c_str()
or data()
is called (at which point &buffer[size()]
begins returning a reference to it instead of an alternate location).