In N3092, it is part of the basic_string template (what it's not in
ours?) and is discussed in 21.4.7:
21.4.7.1 basic_string accessors [string.accessors]
const charT* c_str() const;
const charT* data() const;
1 Returns: a pointer p such that p + i == &operator[](i) for each i in
[0,size()].
2 Throws: nothing.
3 Complexity: constant time.
4 Requires: The program shall not alter any of the values stored in
the character array.
A very long time ago (the source file is dated 12/17/00 -- yes, that's
over 11 years ago!), I implemented a /non-template version/ of class
string (IIRC, this was because Watcom did not, at the time I started
it, provide one).
FWIW, my implementation /copied/ the current content of the string
into a separate buffer and returned a pointer to that buffer.
NOTE (important): since the data in a string can be anything, it can
both include null bytes and not be terminated by one. At least, the
string class I wrote would allow this. I copied all the bytes
controlled by the string and then appended a null byte if one was not
already present.
This, of course, is one reason I returned a pointer to a copy: I
didn't want to insert null bytes into the actual data, since I would
then have to remove them when adding new text (I think I tried that
originally but, trust me on this, it wasn't worth the effort,
particularly when it is kept in mind that the data in a string can
include null bytes).
And, of course, the fourth condition would be violated if a null were
added at the end of the actual data.
This means that each value returned by c_str() is a snapshot, as it
were, of the value of the string object at the time it is invoked.
This copy will not be affected by subsequent use of string, nor will
modifying this copy affect the string object in any way, which may or
may not be what is needed.
However, if you simple malloc a buffer and return its address and use
that in a C++ output sequence, memory will be leaked. This is probably
why I used this dodge at the top of the string class:
private:
mutable vector<char> cStringData; // Used
by c_str() only
vector<char> theData; //
Contains the data
That is, on the one hand, each time c_str() was invoked, the content
potentially overwrote the prior content (so that, if the programmer
wanted to save the state of a string object, it would be necessary to
make another copy) but, on the other hand, any memory allocated was
released when the string object was destructed, thus allowing c_str()
to be used in C++ output sequences.
Since cStringData was initialized by
cStringData = theData;
this also requires the assignment operator for vector<char> to do a
deep copy, but perhaps that is a given (it has been a long long time
since I knew this stuff).
In fact, you might as well see the rest of the body:
vector<char>::iterator theEnd(cStringData.end());
if(empty() || (*(--theEnd) != '\0'))
{
cStringData.insert(cStringData.end(), 1, '\0');
}
return(cStringData.begin());
since it might still work even when embedded in the basic_string
template. That is a decrement operator in front of theEnd, by the way
(in the font I am using, it looks like a single long line, which might
be unclear if your reader does the same thing.) Well, you'd need to
add some spaces here and there to comply with the OW style guide, but
that is relatively minor. As shown, f there is no data, a pointer to
an empty string is returned.
--
"Nature must be explained in
her own terms through
the experience of our senses."