Ответ 1
Почему мы не можем писать непосредственно в этот буфер?
Я укажу очевидный момент: потому что он const
. И отбрасывая значение const
, а затем изменяя эти данные... грубо.
Теперь, почему он const
? Это происходит в те дни, когда копирование по-записи считалось хорошей идеей, поэтому std::basic_string
должно было позволить реализациям поддерживать ее. Было бы очень полезно получить неизменяемый указатель на строку (например, для перехода на C-API), не наносив накладные расходы на копию. Поэтому c_str
необходимо вернуть указатель const
.
Что до этого еще const
? Ну... это идет в странную вещь в стандарте: нулевой терминатор.
Это законный код:
std::string stupid;
const char *pointless = stupid.c_str();
pointless
должна быть строкой, завершенной нулем. В частности, это должен быть указатель на символ NUL. Итак, откуда появился символ NUL? Для реализации std::string
существует несколько способов реализации этой функции:
- Используйте мелкоструйную оптимизацию, которая является общей методикой. В этой схеме каждая реализация
std::string
имеет внутренний буфер, который он может использовать для одного символа NUL. - Возвращает указатель на статическую память, содержащую символ NUL. Поэтому каждая реализация
std::string
возвращает тот же указатель, если это пустая строка.
Всем не нужно принудительно внедрять SSO. Поэтому комитету по стандартам нужен способ сохранить № 2 на столе. И часть этого дает вам строку const
из c_str()
. И поскольку эта память, скорее всего, реальна const
, а не подделка "Пожалуйста, не изменяйте эту память const
", давая вам изменяемый указатель на нее, это плохая идея.
Конечно, вы все равно можете получить такой указатель, выполнив &str[0]
, но в стандарте очень ясно, что изменение терминатора NUL - это плохая идея.
Теперь, если говорить, совершенно верно изменить указатель &str[0]
и массив символов в нем. Пока вы остаетесь в полуоткрытом диапазоне [0, str.size()
). Вы просто не можете сделать это с помощью указателя, возвращаемого data
или c_str
. Да, хотя стандарт действительно требует, чтобы str.c_str() == &str[0]
был истинным.
Это стандартное для вас.