std::string::reserve и конец строки 0
При предварительном распределении с использованием std::string::reserve
Должен ли я добавить один для прекращения 0
явно во избежание перераспределения и последующего копирования?
Например, зная, что строка "Hello"
длиной 5 будет храниться в std::string str
Должен ли я позвонить str.reserve(6)
?
Если я правильно прочитал стандарт, то я думаю, что ответ должен быть да. За reserve
это говорит
После резерва (), емкость () больше или равна аргументу резерва.
и для capacity
в свою очередь это заявляет
Возвращает: Размер выделенного хранилища в строке.
Однако я не знаком с тонкостями формулировок в стандарте, и я хотел подтвердить свое подозрение.
2 ответа
C++11 указывает (или я читал в нескольких местах, не могу найти эту формулировку в документе n3337?), Что std::string
должен храниться таким образом, чтобы нулевое завершение строки в стиле C не требовало перераспределения.
Конечно, это то, что происходит в библиотеке GNU C++, в функции _S_create:
template<typename _CharT, typename _Traits, typename _Alloc>
typename basic_string<_CharT, _Traits, _Alloc>::_Rep*
basic_string<_CharT, _Traits, _Alloc>::_Rep::
_S_create(size_type __capacity, size_type __old_capacity,
const _Alloc& __alloc)
....
// NB: Need an array of char_type[__capacity], plus a terminating
// null char_type() element, plus enough for the _Rep data structure.
// Whew. Seemingly so needy, yet so elemental.
size_type __size = (__capacity + 1) * sizeof(_CharT) + sizeof(_Rep);
+ 1
там, чтобы покрыть завершающий символ.
Затем он продолжает "регулировать" размер, чтобы сделать его более оптимальным, используя несколько угаданных констант для minimum allocation
а также page_size
, но это всегда будет как минимум __size
и всегда добавляет 1
освободить место для прекращения.
Чтобы выяснить, что это "всегда" делает это, вы должны следовать коду и обнаружить, что звонки сделаны _M_clone
всякий раз, когда строка должна быть перераспределена, и _M_clone
по очереди звонки _S_create
, Код нелегко читать, так как он написан для того, чтобы следовать стандарту и быть эффективным, а не для нас, простых смертных, его прочитать.
Легче увидеть это c_str
ничего не выделяет здесь:
const _CharT*
c_str() const _GLIBCXX_NOEXCEPT
{ return _M_data(); }
который затем вызывает:
_CharT*
_M_data() const _GLIBCXX_NOEXCEPT
{ return _M_dataplus._M_p; }
Другими словами, просто возвращает указатель на актуальную строку.
Returns: The size of the allocated storage in the string.
Выделенное хранилище в строке этого оператора означает, что строка должна помещаться в выделенном пространстве. "Строка" означает "группу символов с нулем в конце", поэтому также следует включить ноль.