Я читал в нескольких местах, что разница между c_str() и data() (в STL и других реализациях) заключается в том, что c_str() всегда завершается нулем, а data() - нет.
Насколько я видел в реальных реализациях, они либо делают то же самое, либо data() вызывает c_str().
Что мне здесь не хватает? Какой из них правильнее использовать в каких сценариях?





Документация верна. Используйте c_str(), если вам нужна строка с завершающим нулем.
Если разработчики реализовали data() в терминах c_str(), вам не о чем беспокоиться, все равно используйте data(), если вам не нужно, чтобы строка заканчивалась нулем, в некоторых реализациях это может оказаться лучше, чем c_str ().
строки не обязательно должны состоять из символьных данных, они могут состоять из элементов любого типа. В этих случаях data() имеет большее значение. c_str(), на мой взгляд, действительно полезен только тогда, когда элементы вашей строки основаны на символах.
Дополнительный: Начиная с C++ 11, обе функции должны быть одинаковыми. то есть data теперь должен быть завершен нулем. Согласно cppreference: «Возвращаемый массив заканчивается нулем, то есть data () и c_str () выполняют одну и ту же функцию».
Даже зная, что вы видели, что они делают то же самое или что .data () вызывает .c_str (), неверно предполагать, что это будет иметь место для других компиляторов. Также возможно, что ваш компилятор изменится с будущим выпуском.
2 причины использовать std :: string:
std :: string может использоваться как для текстовых, так и для произвольных двоичных данных.
//Example 1
//Plain text:
std::string s1;
s1 = "abc";
//Example 2
//Arbitrary binary data:
std::string s2;
s2.append("a\0b\0b\0", 6);
Вы должны использовать метод .c_str (), когда используете свою строку в качестве примера 1.
Вы должны использовать метод .data (), когда используете свою строку в качестве примера 2. Не потому, что использовать .c_str () в этих случаях опасно, а потому, что это более очевидно, что вы работаете с двоичными данными для других, рассматривающих ваш код.
Возможная ошибка при использовании .data ()
Следующий код неверен и может вызвать segfault в вашей программе:
std::string s;
s = "abc";
char sz[512];
strcpy(sz, s.data());//This could crash depending on the implementation of .data()
Почему разработчики часто заставляют .data () и .c_str () делать одно и то же?
Потому что это более эффективно. Единственный способ заставить .data () возвращать что-то, что не завершается нулем, - это скопировать .c_str () или .data () их внутренний буфер или просто использовать 2 буфера. Наличие одного буфера с завершающим нулем всегда означает, что вы всегда можете использовать только один внутренний буфер при реализации std :: string.
Фактически, смысл .data () в том, что он не должен копировать внутренний буфер. Это означает, что реализации не нужно тратить символ на \ 0, пока он не понадобится. Вам никогда не понадобятся два буфера: если вы ДЕЙСТВИТЕЛЬНО вызываете .c_str (), добавьте в буфер \ 0. .data () все еще может возвращать этот буфер.
Полностью согласен, было бы смешно использовать 2 буфера. Откуда вы знаете, почему был предназначен .data?
@ BrianR.Bondy Я пробовал этот код: .. auto str = string {"Test \ 0String!" }; cout << "DATA:" << str.data () << endl; Результатом будет «Тест», а не вся строка. Что я сделал не так?
Последняя часть неверна, данные и c_str могут использовать один и тот же буфер без завершения 0 - c_str может просто добавить 0 при первом вызове.
хедз-ап, C++ 11 сделал .data () псевдонимом для .c_str ()
Цитата из ANSI ISO IEC 14882 2003 (Стандарт C++ 03):
21.3.6 basic_string string operations [lib.string.ops]
const charT* c_str() const;
Returns: A pointer to the initial element of an array of length size() + 1 whose first size() elements
equal the corresponding elements of the string controlled by *this and whose last element is a
null character specified by charT().
Requires: The program shall not alter any of the values stored in the array. Nor shall the program treat the
returned value as a valid pointer value after any subsequent call to a non-const member function of the
class basic_string that designates the same object as this.
const charT* data() const;
Returns: If size() is nonzero, the member returns a pointer to the initial element of an array whose first
size() elements equal the corresponding elements of the string controlled by *this. If size() is
zero, the member returns a non-null pointer that is copyable and can have zero added to it.
Requires: The program shall not alter any of the values stored in the character array. Nor shall the program
treat the returned value as a valid pointer value after any subsequent call to a non- const member
function of basic_string that designates the same object as this.
На него уже был дан ответ, несколько замечаний о цели: Свобода реализации.
std::string операции - например, итерация, конкатенация и мутация элементов - нулевой терминатор не нужен. Если вы не передадите string функции, ожидающей строку с нулевым завершением, его можно пропустить.
Это позволило бы реализации иметь подстроки, совместно использующие фактические строковые данные: string::substr может внутренне хранить ссылку на совместно используемые строковые данные и начальный / конечный диапазон, избегая копирования (и дополнительного выделения) фактических строковых данных. Реализация отложит копирование до тех пор, пока вы не вызовете c_str или не измените какую-либо из строк. Никакая копия не будет сделана, если будут просто прочитаны задействованные строки.
(реализация копирования при записи не очень интересна в многопоточных средах, плюс типичная экономия памяти / распределения сегодня не стоит более сложного кода, поэтому это делается редко).
Точно так же string::data допускает другое внутреннее представление, например веревка (связанный список отрезков струны). Это может значительно улучшить операции вставки / замены. опять же, список сегментов должен быть свернут до одного сегмента, когда вы вызываете c_str или data.
В С ++ 11 / С ++ 0xdata() и c_str() больше не отличаются. Таким образом, data() также должен иметь нулевое завершение в конце.
21.4.7.1
basic_stringaccessors [string.accessors]
const charT* c_str() const noexcept;
const charT* data() const noexcept;1 Returns: A pointer p such that
p + i == &operator[](i)for eachiin[0,size()].
21.4.5 basic_string element access [string.access]
const_reference operator[](size_type pos) const noexcept;1 Requires: pos <= size(). 2 Returns:
*(begin() + pos) if pos < size(), otherwise a reference to an object of type T with valuecharT();the referenced value shall not be modified.
Что, если строка состоит из несимвольных данных, что допустимо для строковых данных AFAIK, включая null?
@taz Даже при хранении двоичных данных C++ 11 требует, чтобы std::string выделял дополнительный char для завершающего '\0'. Когда вы выполняете std::string s("\0");, как s.data()[0], так и s.data()[1] гарантированно оценивают значение 0.
Все предыдущие комментарии согласованы, но я также хотел бы добавить, что начиная с C++ 17 str.data () возвращает char * вместо const char *
Обе перегрузки const и non-const доступны начиная с C++ 17.
Дополнительно 2: Начиная с C++ 17, теперь также есть неконстантная перегрузка для
.data(), поэтому они больше не эквивалентны для неконстантных строк.