std :: string :: c_str & amp; Нулевое окончание

Я прочитал различные описания std::string::c_str в том числе вопросы, поднятые по SO за годы / десятилетия,

Мне нравится это описание для ясности:

Возвращает указатель на массив, который содержит нулевую последовательность
символов (то есть C-строка), представляющих текущее значение
строковый объект. Этот массив содержит одинаковую последовательность символов
которые составляют значение строкового объекта плюс дополнительный
завершающий нулевой символ (‘\ 0’) в конце.

Однако некоторые вещи о назначении этой функции до сих пор неясны.

Вы могли бы быть прощены за то, что c_str может добавить \0 символ до конца строки, который хранится во внутреннем массиве char хост-объекта (std::string):

s[s.size+1] = '\0'

Но похоже std::string объекты по умолчанию обнуляются даже перед вызовом c_str:
введите описание изображения здесь

После просмотра определения:

const _Elem *c_str() const _NOEXCEPT
{   // return pointer to null-terminated nonmutable array
return (this->_Myptr());
}

Я не вижу кода, который бы добавил \0 в конец массива символов. Насколько я могу судить c_str просто возвращает указатель на символ, хранящийся в первом элементе массива, очень похоже на begin() делает. Я даже не вижу код, который проверяет, что внутренний массив завершается \0

Или я что-то упустил?

4

Решение

До C ++ 11 не требовалось std::string (или шаблонный класс std::basic_string — из которых std :: string является экземпляром) хранить завершающий '\0', Это было отражено в различных спецификациях data() а также c_str() функции-члены — data() возвращает указатель на базовые данные (которые не должны были завершаться '\0' а также c_str() вернул копию с прекращением '\0', Тем не менее, в равной степени, не было требования НЕ хранить трейлинг '\0' внутренне (доступ к символам после конца хранимых данных был неопределенным поведением) ….. и, для простоты, некоторые реализации решили добавить завершающий '\0' тем не мение.

С C ++ 11 это изменилось. По сути, data() была указана функция-член, дающая тот же эффект, что и c_str() (то есть возвращаемый указатель на первый символ массива, который имеет завершающий '\0'). Это имеет следствие необходимости трейлинга '\0' на массиве, возвращаемом data()и, следовательно, на внутреннем представлении.

Таким образом, поведение, которое вы видите, соответствует C ++ 11 — один из инвариантов класса является конечным '\0' (т.е. конструкторы гарантируют, что это так, функции-члены, которые изменяют строку, гарантируют, что она остается истинной, и все открытые функции-члены могут полагаться на ее истинность).

Поведение, которое вы видите, не противоречит стандартам C ++ до C ++ 11. Строго говоря, std::string до C ++ 11 не требовалось поддерживать трейлинг '\0' но, в равной степени, разработчик может сделать это.

5

Другие решения

Вы не видите код, который добавляет '\0' до конца последовательности, потому что нулевой символ уже там. Реализация c_str не может вернуть указатель на новый массив, поэтому массив должен храниться в std::string сам объект

Следовательно, у вас есть два правильных подхода для реализации этого:

  1. Всегда хранить '\0' в конце _Myptr() массив символов на стройке, или
  2. Сделайте копию строки по запросу, добавьте '\0' когда c_str() и удалить копию в деструкторе.

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

6

Требование является c_str должен вернуть завершенную нулем cstring. Ничто не говорит о том, что функция должна добавить нулевой терминатор. Большинство реализаций (и я думаю, что все, что хочет быть совместимым со стандартом) хранят нулевой терминатор в базовом буфере, используемом самой строкой. Одна из причин этого заключается в том, что

std::string s;
assert(s[0] == '\0');

Должен работать, так как строка теперь требуется вернуть нулевой терминатор в string[string.size()], Если строка не хранит нулевой терминатор в нижележащем буфере, то [] придется сделать проверку границ, чтобы увидеть, если это в size() и должен вернуться \0,

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector