Что такое std::string:: C str() lifetime?


в одной из моих программ, я должен взаимодействовать с некоторым старым кодом, который работает с 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() в другое место ?

спасибо.

6 86

6 ответов:

The c_str() результат становится недействительным, если std::string уничтожается или если вызывается неконстантная функция-член строки. Так что, как правило, вы хотите, чтобы сделать копию его, если вам нужно держать его вокруг.

в случае вашего примера, похоже, что результаты c_str() используются безопасно, потому что строки не изменяются в то время как в этой области. (Однако мы не знаем, что use_foo() или ~Foo() может делать с этими значениями; если они копируют строки в другом месте, тогда они должны сделать истинный скопировать, а не просто копировать char указатели.)

технически ваш код в порядке.

но вы написали таким образом, что делает его легко сломать кого-нибудь, кто не знает код. Для 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());
}

он действителен до тех пор, пока одно из следующих событий не произойдет с соответствующим

возвращаемое значение c_str () допустимо только до следующего вызова непостоянной функции-члена для той же строки

The const char* вернулся из c_str() действует только до следующего неконстантного вызова

пока строка не уничтожена или не изменена, использование c_str() в порядке. Если строка изменяется с использованием ранее возвращенного c_str() определяется реализация.