Что такое 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()?

Могу ли я сделать что-то вроде этого без облика undefined?

{
  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() в другое место?

Спасибо.

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

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

Ответ 6

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