Что такое время жизни std :: string :: c_str ()? - PullRequest
89 голосов
/ 23 июня 2011

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

Спасибо.

Ответы [ 7 ]

78 голосов
/ 23 июня 2011

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

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

22 голосов
/ 23 июня 2011

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

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

Но если у вас есть константные строки, они вам на самом деле не нужны:

{
  char const* server = "my_server";
  char const* name   = "my_name";

  Foo foo;
  foo.server = server;
  foo.name   = name;

  use_foo(foo);
}

OK. Почему-то вы хотите их в виде строк:
Почему бы не использовать их только при звонке:

{
  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 голосов
/ 23 июня 2011

Он действителен до тех пор, пока одно из следующего не произойдет с соответствующим string объектом:

  • объект уничтожен
  • объект изменен

С вашим кодом все в порядке, если вы не измените эти string объекты после того, как c_str() s скопированы в foo, но до вызова use_foo().

4 голосов
/ 23 июня 2011

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

3 голосов
/ 23 июня 2011

const char*, возвращаемый из c_str(), действителен только до следующего неконстантного вызова объекта std::string. В этом случае у вас все хорошо, потому что ваш std::string все еще находится в области действия в течение времени жизни Foo, и вы не выполняете никаких других операций, которые изменили бы строку при использовании foo.

2 голосов
/ 11 октября 2018

Для полноты вот ссылка и цитата из cppreference.com :

Указатель, полученный из c_str(), может быть признан недействительным по:

  • Передача неконстантной ссылки на строку в любую стандартную библиотечную функцию или
  • Вызов неконстантных функций-членов на string, исключая operator[], at(), front(), back(), begin(), rbegin(), end() и rend().
2 голосов
/ 23 июня 2011

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

...