tags:

views:

128

answers:

4

If I need to get a NUL-terminated char array out of a std::string in a situation where I need to be sure nothing will be allocated, is it safe to use c_str to do so? For example, if I'm inside a destructor and I want to copy some data from a string into a pre-allocated, fixed-size buffer, can I use c_str and be sure it won't throw anything?

+4  A: 

No, the standard gives no such guarantee. The only guarantee in the C++ standard is that the returned value points to a char array with the same contents as the std::string, plus a nul-terminator.

So it would be standards-conforming for an implementation to store its internal representation in some way other than a C-string, and allocate a C-string on the fly when you call c_str, although I'm fairly certain that no widely used STL implementation actually does this.

Now, with respect to C++0x, I have heard (although I am at a loss for finding documentation for this at the moment), that one of the changes is going to be to require that std::string operate on contiguous storage (a similar requirement already exists for std::vector). So in that case, you could access the span from &str[0] through &str[0]+str.length()-1 as if it were a C-string without a nul-terminator.

Tyler McHenry
Regarding the requirement for contiguous storage, yes, C++0x N3126 says, in `21.4.1/5`, "The char-like objects in a basic_string object shall be stored contiguously."
Cubbi
+4  A: 

The standard says that calling c_str() may invalidate references, pointers, and interators referring to the elements of the string, which implies that reallaocation is permitted (21.3/5 "Class template basic_string").

You might want to just call string::copy() to get your copy (you'll need to add the null terminator yourself if you need it).

Michael Burr
The suggestion to use `string::copy()` was particularly useful. Thanks!
Pillsy
+2  A: 

The Standard is silent on this:

21.3.6 [lib.strings.ops]

const charT * c_str () const ; 1 Returns: A pointer to the initial element of an array of length size() + 1 whose first size() elements equal the corresponding elements of the string controlled by *this and whose last element is a null character specified by charT().

2 Requires: The program shall not alter any of the values stored in the array. Nor shall the program treat the returned value as a valid pointer value after any subsequent call to a non-const member function of the class basic_string that designates the same object as this.

It could. That said, Iv'e never seen any implementation that does.

If this is a concern for you, you may want to consider using vector<char> instead of string, and doing something like:

vector<char> chars;
// ...
char* my_str = &chars[0];

The trick here is knowing when & how to deal with the need for '\0'-terminated strings.

John Dibling
+1  A: 

The standard all but explicitly says that a string can allocate memory when you call c_str. In particular, it says (§21.3/5):

References, pointers, and iterators referring to the elements of a basic_string sequence may be invalidated by the following uses of that basic_string object:
[ ... ]
— Calling data() and c_str() member functions.

It gives permission for pointers, references and iterators to be invalidated specifically to allow an implementation to re-allocate the memory used to store the string when you call c_str.

Jerry Coffin