什么是std :: string :: c_str()寿命?


100

在我的一个程序中,我必须与可以使用的一些旧代码交互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()到另一个地方?

谢谢。


当我在函数中定义本地字符串并返回时,发生在我身上.c_str()。我不明白为什么有时有时只得到字符串的一部分,直到我知道字符串const char*不会永远存在,而是直到字符串被销毁为止
SomethingSomething 2014年

Answers:


85

所述c_str()如果结果变为无效std::string被破坏,或如果字符串的非const成员函数被调用。因此,如果您需要保留它,通常会希望对其进行复制。

在您的示例中,似乎c_str()安全地使用的结果,因为在该范围内未修改字符串。(但是,我们不知道这些值在做什么use_foo()~Foo()可能在做什么;如果它们将字符串复制到其他地方,则它们应该进行真实复制,而不仅仅是复制char指针。)


如果std :: string对象是超出范围或正在调用线程创建函数的自动对象,则c_str()指针可能无效。
GuruM

你能解释一下non-const member function of the string is called.吗?
Mathew Kurian

2
“非常量成员函数”是任何未用const关键字标记的成员函数。此类函数可能会使字符串的内容发生变化,在这种情况下,字符串可能需要为所返回的字符串的以null终止的版本重新分配内存c_str()。例如,size()length()const,因此您可以调用它们而不必担心字符串更改,但是clear()不是const
克里斯托弗·约翰逊

23

从技术上讲,您的代码很好。

但是您所编写的方式很容易使不知道该代码的人破解。对于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());
}

7

它有效,直到相应的string对象发生以下情况之一:

  • 对象被破坏
  • 对象被修改

除非您string在将c_str()s复制到之后foouse_foo()被调用之前修改了这些对象,否则您的代码会很好。


4

c_str()的返回值仅在下一次针对相同字符串的非恒定成员函数的调用之前才有效


3

const char*返回了c_str()才有效,直到下一个非const调用std::string对象。在这种情况下,您会很好,因为std::stringFoofoo 的生命周期内您仍处于范围内,并且您在使用foo时不会进行任何其他会更改字符串的操作。


2

只要不破坏或修改字符串,使用c_str()即可。如果使用先前返回的字符串修改了字符串,则实现定义为c_str()。


2

为了完整起见,这是cppreference.com参考和引用

从中获得的指针c_str()可能会因以下原因而失效:

  • 将对字符串的非常量引用传递给任何标准库函数,或者
  • 上主叫非const成员函数string,不包括operator[]at()front()back()begin()rbegin()end()rend()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.