Що таке життя 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.