109

在我的一个程序中,我必须与一些适用于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()到另一个地方?

谢谢你。

4

7 回答 7

92

如果 被销毁或调用字符串的非常量成员函数,则c_str()结果无效。std::string所以,如果你需要保留它,通常你会想要复制它。

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

于 2011-06-23T15:15:29.950 回答
26

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

但是您编写的方式很容易让不知道代码的人破解。对于 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());
}
于 2011-06-23T16:07:16.210 回答
7

string在相应的对象发生以下情况之一之前,它是有效的:

  • 对象被销毁
  • 对象被修改

除非您在s 被复制到但在被调用之前修改这些string对象,否则您的代码没问题。c_str()foouse_foo()

于 2011-06-23T15:15:23.710 回答
4

c_str() 的返回值仅在下一次调用同一字符串的非常量成员函数之前有效

于 2011-06-23T15:15:11.740 回答
3

const char*返回的 from仅c_str()在下一次对该std::string对象的非常量调用之前有效。在这种情况下,您很好,因为您std::string的生命周期仍在范围内,Foo并且您没有执行任何其他会在使用 foo 时更改字符串的操作。

于 2011-06-23T15:18:04.700 回答
2

只要字符串没有被破坏或修改,使用 c_str() 就可以了。如果使用先前返回的 c_str() 修改了字符串,则实现定义。

于 2011-06-23T15:15:07.023 回答
2

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

获得的指针c_str()可能会通过以下方式无效:

  • 将对字符串的非常量引用传递给任何标准库函数,或
  • string在、operator[]at()front()back()begin()rbegin()end()上调用非常量成员函数rend()
于 2018-10-11T18:12:41.523 回答