标准::字符串::保留和字符串结尾 0
std::string::reserve and end-of-string 0
使用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 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.
字符串中的已分配存储空间该语句表示该字符串应适合分配的空间。"字符串"表示"以零结尾的字符组",因此也应包括零。