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

kcwpcxri  于 2022-11-19  发布在  其他
关注(0)|答案(7)|浏览(247)

在我的一个程序中,我必须与一些使用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()的结果复制到另一个地方吗?

jum4pzuy

jum4pzuy1#

如果std::string被破坏或者调用了字符串的非常数成员函数,那么c_str()的结果就无效了。所以,如果你需要保存它,通常你会想做一个副本。
在您的示例中,c_str()的结果似乎被安全地使用了,因为字符串在该作用域中没有被修改。(但是,我们不知道use_foo()~Foo()可能对这些值做了什么;如果他们将字符串复制到其他地方,那么他们应该执行真正的 * 复制 *,而不仅仅是复制char指针。)

evrscar2

evrscar22#

从技术上讲,您的代码没有问题。

但是您的编写方式很容易让不懂代码的人破解。对于c_str(),唯一安全的用法是将其作为参数传递给函数。否则,您将面临维护问题。

例一:

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

bq9c1y663#

在Map的string对象发生下列其中一种情况之前,它一直有效:

  • 对象被破坏
  • 修改对象

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

rxztt3cl

rxztt3cl4#

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

cyvaqqii

cyvaqqii5#

c_str()返回的const char*只在下一次对std::string对象的非常数调用之前有效。在这种情况下,你没有问题,因为你的std::stringFoo的生存期内仍然在作用域中,而且你在使用foo时没有做任何其他会改变字符串的操作。

1mrurvl1

1mrurvl16#

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

3htmauhk

3htmauhk7#

为了完整起见,这里有一个reference and quotation from cppreference.com
c_str()获得的指针可以通过以下方式无效:

  • 将对字符串的非常数引用传递给任何标准库函数,或者
  • string上呼叫非常数成员函式,不包括operator[]at()front()back()begin()rbegin()end()rend()

相关问题