tags:

views:

869

answers:

7

std::string provides const char* c_str ( ) const which:

Get C string equivalent

Generates a null-terminated sequence of characters (c-string) with the same content as the string object and returns it as a pointer to an array of characters.

A terminating null character is automatically appended.

The returned array points to an internal location with the required storage space for this sequence of characters plus its terminating null-character, but the values in this array should not be modified in the program and are only granted to remain unchanged until the next call to a non-constant member function of the string object.

Why don't they just define operator const char*() const {return c_str();} ?

+2  A: 

That's probably because this conversion would have surprising and peculiar semantics. Particularly, the fourth paragraph you quote.

Another reason is that there is an implicit conversion const char* -> string, and this would be just the converse, which would mean strange behavior wrt overload resolution (you shouldn't make both implicit conversions A->B and B->A).

jpalecek
i know the experts knew what they are doing, but it strikes me that they would make the string class so hard to use without good reason.
Dustin Getz
I wouldn't say "so hard to use". But if you find typing 7 characters hard, well...
jpalecek
If you find yourself converting to char* often, you probably need to rethink your design.
rmeador
@rmeador: it would be easier to avoid converting to char* if the *C++ standard library* accepted std::string filenames ...
Porculus
+11  A: 

From the C++ Programming Language 20.3.7 (emphasis mine):

Conversion to a C-style string could have been provided by an operator const char*() rather than c_str(). This would have provided the convenience of an implicit conversion at the cost of surprises in cases in which such a conversion was unexpected.

sixlettervariables
Care to explain what would be the costly surprise?
ChrisW
1. When conversion to a C string causes a memory reallocation because std::string doesn't necessarily store a NULL terminator2. When the std::string goes out of scope and you are left with a dangling pointer to freed memory
Clay
I think the short answer is with resolving overloads. Additionally std::string can hold a \0 character that doesn't mean the end of the std::string.
sixlettervariables
It is a matter of overloads. "char *" doesn't behave like any sensible person would expect a string to, and it's useful to have expressions like "string_1 - string_2" or "string_1 - 2" be flagged as compiler errors rather than compile to nonsense.
David Thornley
+1  A: 

Because C-style strings are a source of bugs and many security problems it's way better to make the conversion explicitly.

hyperboreean
Irrelevant here. The poster is apparently going to use C-style strings anyway.
David Thornley
+4  A: 

Because implicit conversions almost never behave as you expect. They can give surprising results in overload resolution, so it's usually better to provide an explicit conversion as std::string does.

jalf
+4  A: 

The Josuttis book says the following:

This is for safety reasons to prevent unintended type conversions that result in strange behavior (type char * often has strange behavior) and ambiguities (for example, in an expression that combines a string and a C-string it would be possible to convert string into char * and vice versa).

Kristo
I was just typing the exact same quote :)
17 of 26
+3  A: 
Chestal
+1 for providing concrete examples. Anybody can say "Oh it's dangerous", but without examples it is hard to understand how.
Mark Ransom
+2  A: 

I addition to the rationale provided in the specification (unexpected surprises), if you're mixing C API calls with std::string, you really need to get into the habit of using the ::c_ctr() method. If you ever call a varargs function (eg: printf, or equivalent) which requires a const char*, and you pass a std::string directly (without calling the extraction method), you won't get a compile error (no type checking for varargs functions), but you will get a runtime error (class layout is not binary identical to a const char*).

Incidentally, CString (in MFC) takes the opposite approach: it has an implicit cast, and the class layout is binary-compatible with const char* (or const w_char*, if compiling for wide character strings, ie: "Unicode").

Nick
I work with g++ and it always flags passing any type of object as varargs argument with a warning and a message: if this piece of code gets run, the program will terminate unexpectedly. It is not mandated in the standard but should be flagged by most compilers
David Rodríguez - dribeas
I was always curious how CString got away with this - thanks for the insight.
Mark Ransom