问题
In one of my programs, I have to interface with some legacy code that works with const char*.
Lets say I have a structure which looks like:
struct Foo
{
const char* server;
const char* name;
};
My higher-level application only deals with std::string, so I thought of using std::string::c_str() to get back const char* pointers.
But what is the lifetime of c_str() ?
Can I do something like this without facing undefined behavior ?
{
std::string server = \"my_server\";
std::string name = \"my_name\";
Foo foo;
foo.server = server.c_str();
foo.name = name.c_str();
// We use foo
use_foo(foo);
// Foo is about to be destroyed, before name and server
}
Or am I supposed to immediately copy the result of c_str() to another place ?
Thank you.
回答1:
The c_str() result becomes invalid if the std::string is destroyed or if a non-const member function of the string is called. So, usually you will want to make a copy of it if you need to keep it around.
In the case of your example, it appears that the results of c_str() are used safely, because the strings are not modified while in that scope. (However, we don't know what use_foo() or ~Foo() might be doing with those values; if they copy the strings elsewhere, then they should do a true copy, and not just copy the char pointers.)
回答2:
Technically your code is fine.
BUT you have written in such a way that makes it easy to break for somebody that does not know the code. For c_str() the only safe usage is when you pass it as a parameter to a function. Otherwise you open yourself up-to maintenance problems.
Example 1:
{
std::string server = "my_server";
std::string name = "my_name";
Foo foo;
foo.server = server.c_str();
foo.name = name.c_str();
//
// Imagine this is a long function
// Now a maintainer can easily come along and see name and server
// and would never expect that these values need to be maintained as
// const values so why not re-use them
name += "Martin";
// Oops now its broken.
// We use foo
use_foo(foo);
// Foo is about to be destroyed, before name and server
}
So for maintenance make it obvious:
Better solution:
{
// Now they can't be changed.
std::string const server = "my_server";
std::string const name = "my_name";
Foo foo;
foo.server = server.c_str();
foo.name = name.c_str();
use_foo(foo);
}
But if you have const strings you don't actually need them:
{
char const* server = "my_server";
char const* name = "my_name";
Foo foo;
foo.server = server;
foo.name = name;
use_foo(foo);
}
OK. For some reason you want them as strings:
Why not use them only in the call:
{
std::string server = "my_server";
std::string name = "my_name";
// guaranteed not to be modified now!!!
use_foo(Foo(server.c_str(), name.c_str());
}
回答3:
It is valid until one of the following happens to the corresponding string object:
- the object is destroyed
- the object is modified
You're fine with your code unless you modify those string objects after c_str()s are copied into foo but before use_foo() is called.
回答4:
Return value of c_str() is valid only until the next call of a nonconstant member function for the same string
回答5:
The const char* returned from c_str() is only valid until the next non-const call to the std::string object. In this case you're fine because your std::string is still in scope for the lifetime of Foo and you aren't doing any other operations that would change the string while using foo.
回答6:
As long as the string isn't destroyed or modified, using c_str() is OK. If the string is modified using a previously returned c_str() is implementation defined.
回答7:
For completeness, here's a reference and quotation from cppreference.com:
The pointer obtained from
c_str()may be invalidated by:
- Passing a non-const reference to the string to any standard library function, or
- Calling non-const member functions on the
string, excludingoperator[],at(),front(),back(),begin(),rbegin(),end()andrend().
来源:https://stackoverflow.com/questions/6456359/what-is-stdstringc-str-lifetime