Std: : string: : c_str()的结果的生命周期是多少?

在我的一个程序中,我必须与一些与 const char*一起工作的遗留代码进行接口。

假设我有一个这样的结构:

struct Foo
{
const char* server;
const char* name;
};

我的高级应用程序只处理 std::string,所以我考虑使用 std::string::c_str()来返回 const char*指针。

但是 c_str()的寿命是多少呢?

我能不面对未定义行为做这种事吗?

{
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
}

或者我应该立即将 c_str()的结果复制到另一个地方?

32689 次浏览

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.

Return value of c_str() is valid only until the next call of a nonconstant member function for the same string

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.

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.)

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.

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());
}

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, excluding operator[], at(), front(), back(), begin(), rbegin(), end() and rend().