Строка c_str () vs. data ()

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
111
0
49 702
6

Ответы 6

Документация верна. Используйте c_str(), если вам нужна строка с завершающим нулем.

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

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

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

Дополнительно 2: Начиная с C++ 17, теперь также есть неконстантная перегрузка для .data(), поэтому они больше не эквивалентны для неконстантных строк.

Deduplicator 20.12.2018 04:22

Даже зная, что вы видели, что они делают то же самое или что .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 () все еще может возвращать этот буфер.

MSalters 13.10.2008 14:46

Полностью согласен, было бы смешно использовать 2 буфера. Откуда вы знаете, почему был предназначен .data?

Brian R. Bondy 13.10.2008 18:18

@ BrianR.Bondy Я пробовал этот код: .. auto str = string {"Test \ 0String!" }; cout << "DATA:" << str.data () << endl; Результатом будет «Тест», а не вся строка. Что я сделал не так?

programmer 19.09.2015 18:45

Последняя часть неверна, данные и c_str могут использовать один и тот же буфер без завершения 0 - c_str может просто добавить 0 при первом вызове.

Remember Monica 25.03.2018 03:54

хедз-ап, C++ 11 сделал .data () псевдонимом для .c_str ()

hanshenrik 03.07.2019 01:51

Цитата из 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_string accessors [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 each i in [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 value charT(); the referenced value shall not be modified.

Что, если строка состоит из несимвольных данных, что допустимо для строковых данных AFAIK, включая null?

taz 30.07.2013 20:51

@taz Даже при хранении двоичных данных C++ 11 требует, чтобы std::string выделял дополнительный char для завершающего '\0'. Когда вы выполняете std::string s("\0");, как s.data()[0], так и s.data()[1] гарантированно оценивают значение 0.

bcrist 15.09.2013 11:30

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

Обе перегрузки const и non-const доступны начиная с C++ 17.

Gupta 18.09.2019 15:19

Другие вопросы по теме