Что такое 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.