String и const char * и .c_str()?
У меня возникла странная проблема, и я хочу знать, почему она ведет себя так. У меня есть класс, в котором есть функция-член, которая возвращает std::string
. Моя цель - преобразовать этот string
в const char*
, поэтому я сделал следующее
const char* c;
c = robot.pose_Str().c_str(); // is this safe??????
udp_slave.sendData(c);
Проблема в том, что я получаю странный персонаж на стороне мастера. Однако, если я сделаю следующее
const char* c;
std::string data(robot.pose_Str());
c = data.c_str();
udp_slave.sendData(c);
Я получаю то, что ожидаю. Мой вопрос в чем разница между двумя вышеупомянутыми методами?
Ответы
Ответ 1
Это вопрос указывать на временное.
Если вы возвращаетесь по значению, но не сохраняете string
, он исчезает следующей точкой последовательности (точкой с запятой).
Если вы храните его в переменной, то указатель указывает на то, что на самом деле существует в течение всего вашего udp send
Рассмотрим следующее:
int f() { return 2; }
int*p = &f();
Теперь это кажется глупым на его лице, не так ли? Вы указываете на значение, которое копируется из f
. Вы не представляете, как долго он будет жить.
Ваш string
будет таким же образом.
Ответ 2
.c_str()
возвращает адрес char const*
по значению, что означает, что он получает копию указателя. Но после этого фактический массив символов, на который он указывает, уничтожается. Вот почему вы получаете мусор. В последнем случае вы создаете новую строку с этим символьным массивом, копируя символы из фактического местоположения. В этом случае, хотя фактический массив символов уничтожен, копия остается в строковом объекте.
Ответ 3
Вы не можете использовать данные, на которые указывает c_str()
за время жизни объекта std::string
, откуда он пришел. Иногда неясно, какова продолжительность жизни, например, код ниже. Решение также показано:
#include <string>
#include <cstddef>
#include <cstring>
std::string foo() { return "hello"; }
char *
make_copy(const char *s) {
std::size_t sz = std::strlen(s);
char *p = new char[sz];
std::strcpy(p, s);
return p;
}
int
main() {
const char *p1 = foo().c_str(); // Whoops, can't use p1 after this statement.
const char *p2 = make_copy(foo().c_str()); // Okay, but you have to delete [] when done.
}
Ответ 4
Из c_str():
Указатель, полученный из c_str(), может быть недействительным:
- Передача неконстантной ссылки на строку на любую стандартную библиотечную функцию или
- Вызов неконстантных функций-членов в строке, исключая оператор [], at(), front(), back(), begin(), rbegin(), end() и ренд().
Это означает, что если строка, возвращаемая символом robot.pose_Str()
, будет уничтожена или изменена любой неконстантной функцией, указатель на строку будет признан недействительным. Поскольку вы можете вернуть временную копию с robot.pose_Str()
, возврат c_str()
на нее должен быть недействительным сразу после этого вызова.
Тем не менее, если вы вернете ссылку на внутреннюю строку, которую вы можете удерживать, вместо временной копии вы можете:
- убедитесь, что он будет работать, если ваша функция
udp_send
является синхронной;
- или полагаться на недопустимый указатель и, таким образом, испытывать поведение undefined, если
udp_send
может завершиться после некоторой возможной модификации внутреннего содержимого исходной строки.
Ответ 5
Q
const char* c;
c = robot.pose_Str().c_str(); // is this safe??????
udp_slave.sendData(c);
А
Это потенциально опасно. Это зависит от того, что возвращает robot.pose_Str()
. Если срок службы возвращаемого std::string
длиннее срока службы c
, то он безопасен. В противном случае это не так.
Вы сохраняете адрес в c
, который будет недействительным сразу после завершения выполнения инструкции.
std::string s = robot.pose_Str();
const char* c = s.c_str(); // This is safe
udp_slave.sendData(c);
Здесь вы сохраняете адрес в c
, который будет действительным модулем, который вы выберете из области, в которой определены s
и c
.