Почему std::vector:: данные и std::string:: данные разные?

Векторный новый метод data() предоставляет версию const и non-const.
Однако метод string data() предоставляет только версию const.

Я думаю, что они изменили формулировку о std::string, чтобы теперь символы были смежными (например, std::vector).

Был ли std::string::data просто пропущен? Или это хорошая причина только разрешить доступ const к строкам, лежащим в основе символов?

note: std::vector::data имеет другую приятную функцию, но не undefined поведение вызывает data() на пустой вектор. Если &vec.front() - это undefined поведение, если оно пустое.

Ответ 1

В С++ 98/03 была хорошая причина не иметь неконстантный data() из-за того, что строка часто выполнялась как COW. Неконстантный data() потребовал бы, чтобы копия была сделана, если refcount был больше 1. Хотя это возможно, это не было сочтено желательным в С++ 98/03.

В октябре 2005 года комитет проголосовал в LWG 464, который добавил константу и не const data() в vector, и добавлен const и не const at() в map. В то время string не было изменено, чтобы запретить COW. Но позже, С++ 11, COW string больше не соответствует. Спецификация string также была затянута в С++ 11, так что она должна быть непрерывной, и всегда существует завершающий нуль, открытый operator[](size()). В С++ 03 завершающий нуль гарантировался только при перегрузке константы operator[].

Короче говоря, неконстант data() выглядит намного более разумным для С++ 11 string. Насколько я знаю, это никогда не предлагалось.

Обновление

charT* data() noexcept;

был добавлен basic_string в рабочий проект С++ 1z N4582 David Sankel P0272R1 на собрании в Джексонвилле в феврале 2016 года.

Хорошая работа Дэвид!

Ответ 2

Исторически строковые данные не были константами, поскольку предотвращали бы некоторые общие оптимизации, такие как copy-on-write (COW). Это сейчас, IIANM, гораздо реже, потому что он плохо работает с многопоточными программами.

Кстати, да, теперь они должны быть смежными:

[string.require].5: Объекты char в объекте basic_string сохраняются смежно. То есть для любой basic_string объект s, тождество & * (s.begin() + n) == & * s.begin() + n выполняется для всех значений n таких, что 0 <= n < s.size().

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

std::string ret;
strcpy(ret.data(), "whatthe...");

Или любая другая функция, которая возвращает предварительно выделенный массив char.

Ответ 3

Хотя я не настолько хорошо разбираюсь в стандарте, это может быть связано с тем, что std::string не должен содержать данные с нулевым завершением, но он может и не должен содержать явное поле длины, но оно может. Таким образом, изменение данных переноса и, например, добавление '\0' в середине может привести к тому, что поле длины строк не синхронизируется с фактическими данными char и, таким образом, оставит объект в недопустимом состоянии.

Ответ 4

@Christian Rau

С момента, когда оригинальный Plauger (примерно в 1995 году, я думаю) класс string был STL-ized комитетом (превращенный в последовательность, templatified), std::string всегда был std::vector плюс связанный с строкой материал ( преобразование из/в 0-конец, конкатенация,...) плюс некоторые странности, такие как COW, которые на самом деле " Копировать на запись и на не const begin()/end()/operator[]".

Но в конечном итоге a std::string действительно является std::vector под другим именем, с немного другим фокусом и намерением. Итак:

  • как std::vector, std::string имеет либо элемент данных размера, либо как начальный, так и конечный элементы данных;
  • точно так же, как std::vector, std::string не заботится о значении его элементов, встроенных NUL или других.

std::string не строка C с синтаксическим сахаром, служебные функции и некоторая инкапсуляция, так же как std::vector<T> не T[] с синтаксическим сахаром, служебными функциями и некоторой инкапсуляцией.