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.