In C++11, we know that std::string
is guaranteed to be both contiguous and null-terminated (or more pedantically, terminated by charT()
, which in t
Unfortunately, this is UB, if I interpret the wording correct (in any case, it's not allowed):
§21.4.5 [string.access] p2
Returns:
*(begin() + pos)
ifpos < size()
, otherwise a reference to an object of typeT
with valuecharT()
; the referenced value shall not be modified.
(Editorial error that it says T
not charT
.)
.data()
and .c_str()
basically point back to operator[]
(§21.4.7.1 [string.accessors] p1
):
Returns: A pointer
p
such thatp + i == &operator[](i)
for eachi
in[0,size()]
.
I suppose n3092 isn't current any more but that's what I have. Section 21.4.5 allows access to a single element. It requires pos <= size(). If pos < size() then you get the actual element, otherwise (i.e. if pos == size()) then you get a non-modifiable reference.
I think that as far as the programming language is concerned, a kind of access which could modify the value is considered a modification even if the new value is the same as the old value.
Does g++ have a pedantic library that you can link to?
LWG 2475 made this valid by editing the specification of operator[](size())
(inserted text in bold):
Otherwise, returns a reference to an object of type
charT
with valuecharT()
, where modifying the object to any value other thancharT()
leads to undefined behavior.
According to the spec, overwriting the terminating NUL
should be undefined behavior.
So, the right thing to do would be to allocate length+1
characters in the string, pass the string buffer to the C API, and then resize()
back to length
:
// "+ 1" to make room for the terminating NUL for the C API
std::string str(length + 1);
// Call the C API passing &str[0] to safely write to the string buffer
...
// Resize back to length
str.resize(length);
(FWIW, I tried the "overwriting NUL" approach on MSVC10, and it works fine.)