在我的一个程序中,我必须与一些与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()
的结果复制到另一个地方?
谢谢。
答案 0 :(得分:77)
如果c_str()
被销毁或者字符串的非const成员函数被调用,std::string
结果将变为无效。所以,如果你需要保留它,通常你会想要复制它。
对于您的示例,似乎安全地使用了c_str()
的结果,因为在该范围内不会修改字符串。 (但是,我们不知道use_foo()
或~Foo()
可能对这些值做了什么;如果他们将字符串复制到别处,那么他们应该执行真正的复制,并且不只是复制char
指针。)
答案 1 :(得分:22)
从技术上讲,你的代码很好。
但是你这样写的方式让那些不知道代码的人容易打破。对于c_str(),唯一安全的用法是将它作为参数传递给函数。否则你就会面临维护问题。
示例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
}
因此,对于维护来说,显而易见:
更好的解决方案:
{
// 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);
}
但是如果你有const字符串,你实际上并不需要它们:
{
char const* server = "my_server";
char const* name = "my_name";
Foo foo;
foo.server = server;
foo.name = name;
use_foo(foo);
}
行。出于某种原因,你想要它们作为字符串:
为什么不在电话中使用它们:
{
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());
}
答案 2 :(得分:7)
在相应的string
对象发生以下情况之一之前有效:
除非在将string
复制到c_str()
之后但在调用foo
之前修改这些use_foo()
个对象,否则您的代码就可以了。
答案 3 :(得分:4)
c_str()的返回值仅在下一次调用同一字符串的非常量成员函数之前有效
答案 4 :(得分:3)
从const char*
返回的c_str()
仅在下一次对std::string
对象的非常量调用之前有效。在这种情况下,你很好,因为你的std::string
仍然在Foo
的生命周期的范围内,你没有做任何其他操作,在使用foo时会改变字符串。
答案 5 :(得分:2)
只要不销毁或修改字符串,使用c_str()就可以了。如果使用先前返回的c_str()修改了字符串,则执行定义。
答案 6 :(得分:1)
为完整起见,这里是reference and quotation from cppreference.com:
从
c_str()
获得的指针可能会因以下原因而失效:
- 将对字符串的非常量引用传递给任何标准库函数,或者
- 在
string
上调用非常量成员函数,但不包括operator[]
,at()
,front()
,back()
,begin()
,{{ 1}},rbegin()
和end()
。