标准::字符串::保留和字符串结尾 0

std::string::reserve and end-of-string 0

本文关键字:字符串 结尾 保留 标准      更新时间:2023-10-16

使用std::string::reserve预分配时,我是否必须为终止0显式添加一个以避免重新分配和后续复制?

例如,知道长度为 5 的字符串"Hello"将存储在std::string str中,我必须调用str.reserve(6)吗?

如果我正确阅读了标准,那么我认为答案应该是肯定的。对于reserve它说

在 reserve() 之后,capacity() 大于或等于 reserve 的参数。

对于capacity,它反过来说

返回:字符串中分配的存储的大小。

不过,我不熟悉标准中公式的微妙之处,我想证实我的怀疑。

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 allocationpage_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.

字符串中的已分配存储空间该语句表示该字符串应适合分配的空间。"字符串"表示"以零结尾的字符组",因此也应包括零。