Каково время жизни результата std::string::c_str()?

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

Спасибо.


person ereOn    schedule 23.06.2011    source источник
comment
Это случилось со мной, когда я определил локальную строку в функции и вернул .c_str(). Я не понимал, почему иногда я получаю только части строки, пока не понял, что const char* живет не вечно, а до тех пор, пока строка не будет уничтожена   -  person SomethingSomething    schedule 02.12.2014


Ответы (7)


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

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

person Kristopher Johnson    schedule 23.06.2011
comment
Указатель c_str() может быть недопустимым, если объект std::string является автоматическим объектом, выходящим за пределы области действия или вызывающим функцию создания потока. - person GuruM; 16.10.2012
comment
Не могли бы вы объяснить non-const member function of the string is called.? - person Mathew Kurian; 24.12.2013
comment
Неконстантная функция-член — это любая функция-член, не отмеченная ключевым словом const. Такая функция может изменить содержимое строки, и в этом случае строке может потребоваться перераспределить память для нулевой версии строки, возвращаемой c_str(). Например, size() и length() — это const, поэтому вы можете вызывать их, не беспокоясь об изменении строки, но clear() — это не const. - person Kristopher Johnson; 25.12.2013

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

НО вы написали таким образом, что его легко сломать тому, кто не знает код. Единственное безопасное использование 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());
}
person Martin York    schedule 23.06.2011

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

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

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

person sharptooth    schedule 23.06.2011

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

person DumbCoder    schedule 23.06.2011

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

person AJG85    schedule 23.06.2011

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

person CharlesB    schedule 23.06.2011

Для полноты картины приведем ссылку и цитату с сайта cppreference.com:

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

  • Передача неконстантной ссылки на строку любой стандартной библиотечной функции или
  • Вызов неконстантных функций-членов для string, за исключением operator[], at(), front(), back(), begin(), rbegin(), end() и rend().
person Victor Sergienko    schedule 11.10.2018