Проверьте возвращаемое значение std :: string.c_str () - PullRequest
0 голосов
/ 08 июня 2018

В C ++ Primer 5th Edition написано:

Массив, возвращаемый c_str, не гарантированно действителен бесконечно.

Итак, я сделал тест:

//  c_str exploration
std::string strTest = "This is a test";
const char* s1 = strTest.c_str();
strTest = "This is b test";
std::cout << s1 << std::endl;

Поскольку s1 - указатель, он определенно показывает новое значение.Однако, когда я изменяю значение на строку другой длины, оно обычно показывает какую-то фигню:

//  c_str exploration
std::string strTest = "This is a test";
const char* s1 = strTest.c_str();
strTest = "This is b testsssssssssssssssssssssssssss";
std::cout << s1 << std::endl;

Я подумал, что это потому, что возвращаемая строка C уже зафиксировала позицию конечного нулевого символа, поэтому, когдадлина меняет это делает недействительным все.К моему удивлению, иногда оно остается в силе даже после того, как я изменил строку на новую длину:

//  c_str exploration
std::string strTest = "This is a test";
const char* s1 = strTest.c_str();
strTest = "This is b tests";     // Note the extra s at the end
std::cout << s1 << std::endl;

Второй вопрос:

Я тоже не уверенпочему std::cout << s1 печатает содержимое вместо адреса строки CВ то время как следующий код печатает адрес целого числа, как я ожидал:

int dim = 42;
int* pdim = &dim;
std::cout << pdim << std::endl;

Это печатает символ 'T', как и ожидалось:

std::cout << *s1 << std::endl;

Я предполагаю, что std:: cout выполняет автоматическое преобразование, но, пожалуйста, прочитайте мне больше об этом.

Ответы [ 4 ]

0 голосов
/ 08 июня 2018

Первый вопрос:

c_str Документация гласит следующее, что немного яснее, чем то, что говорится в книге, а также когда она может быть признана недействительной:

Возвращенный указатель может быть признан недействительным при дальнейших вызовах других функций-членов, которые изменяют объект.

Я сделал быстрый тест: при обновлении строки адресs1 указывает на недействительность (т. е. strTest.c_str() возвращает другое значение).

Из документации не совсем понятно, какие функции-члены делают указатель недействительным, но, вероятно, можно с уверенностью сказать, что вы не должны работатьна исходную строковую переменную, если вы собираетесь использовать указатель c_str.

Второй вопрос:

cout выводит конец массива символов изнулевой символЭто не работает, если это целочисленный указатель, как вы уже тестировали.

0 голосов
/ 08 июня 2018

Указатель, возвращаемый из c_str(), гарантированно действителен, пока string не будет изменен.Когда он изменяется (путем вызова неконстантной функции-члена), string может потребоваться выделить новый буфер памяти внутри, что делает указатель недействительным.Когда и как это происходит, точно не указано.

По второму вопросу: существуют различные перегрузки operator <<, причем для string печатается его содержимое.

0 голосов
/ 08 июня 2018

Первый вопрос

Указатель, возвращаемый std::c_str(), остается действительным, если строка не изменена.From cppreference.com :

Указатель, полученный из c_str(), может быть признан недействительным:

  • Передача неконстантной ссылки на строкув любую стандартную библиотечную функцию или
  • Вызов неконстантных функций-членов в строке, исключая operator[], at(), front(), back(), begin(), rbegin(), end() и rend().

В опубликованном вами коде

std::string strTest = "This is a test";
const char* s1 = strTest.c_str();
strTest = "This is b tests";  // This line makes the pointer invalid.

, а затем использование указателя для доступа к строке - неопределенное поведение.

std::cout << s1 << std::endl; // Undefined behavior.

После этого бессмысленно пытаться понять, что делает код.

Второй вопрос

Стандартная библиотека предоставляет функцию перегрузки оператора между std::ostream и * 1038.* поэтому строки в стиле C могут быть напечатаны разумным способом.Когда вы используете:

std::cout << "Hello, World.";

, вы хотите видеть Hello, World. в качестве вывода, а не значение указателя, указывающего на эту строку.

По причинам, выходящим за рамки этого ответаперегрузка этой функции реализована как функция, не являющаяся членом.

template< class CharT, class Traits >
basic_ostream<CharT,Traits>& operator<<( basic_ostream<CharT,Traits>& os, 
                                         const CharT* s );

После того, как все связанные с шаблоном токены заменены, эта строка преобразуется в:

std::ostream& operator<<(std::ostream& os, const char* s );

Вы можете увидеть списокфункций перегрузки, не являющихся членами, на cppreference.com .

0 голосов
/ 08 июня 2018

Второй вопрос

std::ostream::operator<< перегружен для приема целых чисел, const char* и некоторых других базовых типов данных.На самом деле для каждого из них есть немного разные функции, и все, что не является типом примитива, который вы печатаете, должно иметь определенное преобразование в тип.

...