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

100

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

Спасибо.

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

Ответы:

85

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

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

Кристофер Джонсон
источник
Указатель c_str () может быть недопустимым, если объект std :: string является автоматическим объектом, выходящим из области видимости или вызывающим функцию создания потока.
GuruM
Не могли бы вы объяснить non-const member function of the string is called.?
Мэтью Куриан,
2
«Неконстантная функция-член» - это любая функция-член, не отмеченная const ключевым словом. Такая функция может изменить содержимое строки, и в этом случае строке может потребоваться перераспределить память для версии строки с завершающим нулем в конце, возвращаемой функцией c_str(). Например, size()и length()are const, поэтому вы можете вызывать их, не беспокоясь об изменении строки, но clear()это не так const.
Кристофер Джонсон,
23

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

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

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

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

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

острый зуб
источник
4

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

DumbCoder
источник
3

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

AJG85
источник
2

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

CharlesB
источник
2

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

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

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