Строка c_str() против данных ()

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

Что мне здесь не хватает? Какой из них более правильно использовать в каких сценариях?

6 ответов

Документация верна. использование c_str() если вы хотите строку с нулевым символом в конце.

Если разработчики произойдут реализовать data() с точки зрения c_str() вам не нужно беспокоиться, все еще использовать data() если вам не нужна строка с завершающим нулем, в некоторых реализациях может оказаться, что она работает лучше, чем c_str().

Строки не обязательно должны состоять из символьных данных, они могут быть составлены из элементов любого типа. В тех случаях data() более значимым. c_str() по моему мнению, это действительно полезно, когда элементы вашей строки основаны на символах.

Дополнительно: в C++11 и далее обе функции должны быть одинаковыми. т.е. data теперь должен быть нулевым. Согласно cppreference: " Возвращенный массив завершается нулем, то есть data() и c_str () выполняют одну и ту же функцию".

В C++ 11 / C++ 0x, data() а также c_str() больше не отличается. И поэтому data() также должен иметь нулевое завершение в конце.

21.4.7.1 basic_string аксессоры [string.accessors]

const charT* c_str() const noexcept;

const charT* data() const noexcept;

1 Возвращает: указатель p такой, что p + i == &operator[](i) для каждого i в [0,size()],


21.4.5 Доступ к элементу basic_string [string.access]

const_reference operator[](size_type pos) const noexcept;

1 Требуется: pos <= size(). 2 Возвращает: *(begin() + pos) if pos < size()в противном случае ссылка на объект типа T со значением charT(); указанное значение не должно изменяться.

Даже если вы знаете, что вы видели, что они делают то же самое, или что.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 ()

Следующий код неверен и может вызвать ошибку в вашей программе:

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.

Все предыдущие комментарии являются консистенцией, но я также хотел бы добавить, что начиная с C++17, str.data() возвращает char* вместо const char*

На это уже отвечено несколько замечаний о цели: Свобода реализации.

std::string операции - например, итерация, конкатенация и мутация элемента - не нуждаются в нулевом терминаторе. Если вы не пройдете string функции, ожидающей строку с нулем в конце, она может быть опущена.

Это позволило бы реализации иметь подстроки совместно использовать фактические строковые данные: string::substr может внутренне содержать ссылку на совместно используемые строковые данные и начальный / конечный диапазон, избегая копирования (и дополнительного выделения) фактических строковых данных. Реализация будет откладывать копирование до тех пор, пока вы не вызовете c_str или не измените любую из строк. Копия никогда не будет сделана, если только стрингсы будут прочитаны.

(Реализация копирования при записи не многим интересна в многопоточных средах, плюс типичная экономия памяти / выделения сегодня не стоит более сложного кода, поэтому это делается редко).


Так же, string::data позволяет другое внутреннее представление, например, веревка (связанный список сегментов строки). Это может значительно улучшить операции вставки / замены. опять же, список сегментов должен быть свернут в один сегмент при вызове c_str или же data,

Цитата из 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.
Другие вопросы по тегам