Що таке життя 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()в інше місце?

Дякую.


Сталося зі мною, коли я визначив локальну рядок у функції та повернувся .c_str(). Я не розумів, чому іноді я отримую лише частини рядка, доки не зрозумів, що const char*не живе вічно, але поки струна не зруйнована
SomethingSomething

Відповіді:


85

c_str()Результат стає недійсним , якщо std::stringруйнуються або якщо функція - члена Неконстантной рядків називаються. Отже, зазвичай вам потрібно буде зробити його копію, якщо вам потрібно зберегти її.

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


вказівник c_str () може бути недійсним, якщо об'єкт std :: string - це автоматичний об'єкт, що виходить за межі або викликає функцію створення потоку.
ГуруМ

Чи можете ви поясніть, будь ласка non-const member function of the string is called.?
Матвій Куріан

2
"Неконстативна функція члена" - це будь-яка функція члена, яка не позначена constключовим словом. Така функція може вимкнути вміст рядка, і в цьому випадку рядку може знадобитися перерозподілити пам'ять для нульової завершеної версії рядка, повернутої c_str(). Наприклад, size()і length()є 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 () дійсне лише до наступного виклику неконстантної функції члена для тієї ж строки


3

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


2

Поки рядок не знищено або змінено, використовуючи c_str (), це нормально. Якщо рядок модифіковано за допомогою раніше повернутого c_str (), визначено реалізацію.


2

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

Вказівник, отриманий від, c_str()може бути визнаний недійсним:

  • Передавання посилання на рядок без const до будь-якої стандартної функції бібліотеки або
  • Виклик неконстантной функції члена на string, за винятком operator[], at(), front(), back(), begin(), rbegin(), end()і rend().
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.