Почему 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[]
с синтаксическим сахаром, служебными функциями и некоторой инкапсуляцией.