Can I get a non-const C string back from a C++ string?
Const-correctness in C++ is still giving me headaches. In working with some old C code, I find myself needing to assign turn a C++ string object into a C string and assign it to a variable. However, the variable is a char *
and c_str()
returns a const char []
. Is there a good way to get around this without having to roll my own function to do it?
edit: I am also trying to avoid calling new. I will gladly trade slightly more complicated code for less memory leaks.
Solution 1:
C++17 and newer:
foo(s.data(), s.size());
C++11, C++14:
foo(&s[0], s.size());
However this needs a note of caution: The result of &s[0]
/s.data()
/s.c_str()
is only guaranteed to be valid until any member function is invoked that might change the string. So you should not store the result of these operations anywhere. The safest is to be done with them at the end of the full expression, as my examples do.
Pre C++-11 answer:
Since for to me inexplicable reasons nobody answered this the way I do now, and since other questions are now being closed pointing to this one, I'll add this here, even though coming a year too late will mean that it hangs at the very bottom of the pile...
With C++03, std::string
isn't guaranteed to store its characters in a contiguous piece of memory, and the result of c_str()
doesn't need to point to the string's internal buffer, so the only way guaranteed to work is this:
std::vector<char> buffer(s.begin(), s.end());
foo(&buffer[0], buffer.size());
s.assign(buffer.begin(), buffer.end());
This is no longer true in C++11.
Solution 2:
There is an important distinction you need to make here: is the char*
to which you wish to assign this "morally constant"? That is, is casting away const
-ness just a technicality, and you really will still treat the string as a const
? In that case, you can use a cast - either C-style or a C++-style const_cast
. As long as you (and anyone else who ever maintains this code) have the discipline to treat that char*
as a const char*
, you'll be fine, but the compiler will no longer be watching your back, so if you ever treat it as a non-const
you may be modifying a buffer that something else in your code relies upon.
If your char*
is going to be treated as non-const
, and you intend to modify what it points to, you must copy the returned string, not cast away its const
-ness.
Solution 3:
I guess there is always strcpy
.
Or use char*
strings in the parts of your C++ code that must interface with the old stuff.
Or refactor the existing code to compile with the C++ compiler and then to use std:string
.
Solution 4:
There's always const_cast...
std::string s("hello world");
char *p = const_cast<char *>(s.c_str());
Of course, that's basically subverting the type system, but sometimes it's necessary when integrating with older code.