std::basic_string构造函数如何事先知道要保留多少空间
How does the std::basic_string constructor know beforehand how much space to reserve?
std::basic_string
具有以下构造函数,该构造函数使用s
指向的以null结尾的字符串的内容初始化字符串:
std::basic_string(const CharT* s, const Allocator& alloc = Allocator());
但是构造函数如何事先知道在其内部缓冲区中为字符串保留多少空间?
我能想到两种方法:
1)它可以首先遍历整个以null结尾的字符串,直到找到第一个NULL 字符,记住它遍历了多少个字符,并将其用作其内部缓冲区的容量并开始复制。
缺点:它必须读取字符串两次,一次用于计算字符,第二次用于复制字符串。
2)它可以在其内部缓冲区中保留保守的数量,然后开始复制。如果它在缓冲区用完之前命中 NULL 字符,我们就可以了,否则我们需要保留更多空间(再次保留保守数量),然后重复这些步骤。
缺点:如果字符串相当大,则不断重新调整容量的开销可能会变得明显。
那么,一个理智的std::basic_string实现是做什么的(或者这甚至在标准中指定)?
常见的实现会遍历原始字符串来计算长度,然后分配那么多空间。它需要两次执行字符串,但这是一个快速的操作,在某些情况下有硬件支持,即使没有硬件支持操作,与单个内存分配相比,它可能很便宜。
第一种方法是答案。根据标准 §21.4.2:
basic_string(const charT* s, const Allocator& a = Allocator());
9 效果:构造类 basic_string 的对象,并从长度为
traits::length(s)
个字符数组中确定其初始字符串值,其第一个元素由 s...
和
10 备注:使用
traits::length()
.
GCC 的实现是:
template<typename _CharT, typename _Traits, typename _Alloc>
basic_string<_CharT, _Traits, _Alloc>::
basic_string(const _CharT* __s, const _Alloc& __a)
: _M_dataplus(_S_construct(__s, __s ? __s + traits_type::length(__s) :
__s + npos, __a), __a)
{ }
它使用类似于std::char_traits::length
的traits_type::length
来发现 c 样式零终止字符串的长度。
如果你有巨大的条目字符串来传递函数并且你有它的长度,你可以使用另一个重载来获取大小并且不会再次计算它:
basic_string(const CharT* s, size_type count, ...)
您提到的第二种方法还有另一个缺点,它必须缩小分配内存以停止浪费内存。此操作也很昂贵。
我想不出使用第二种方法的理智实现。某些实现(即Visual C++)确实执行默认初始化,这可能会分配一些最小长度(例如 1 或 16),然后调用 assign
,这将获取字符串的长度,如有必要重新分配,然后复制字符串。
许多(如果不是全部)现代编译器将使用手动调整的汇编语言来获取以 null 结尾的字符串的长度,这通常非常快。正在执行分配-复制-重新分配-复制等...真的,至少在我所知道的所有平台上都是疯狂的。
- 有根的二进制搜索树.保留与其父级的链接
- 复制列表初始化的隐式转换的等级是多少
- 为多个会话保留XPtr
- while循环中while循环的时间复杂度是多少
- 如何检查一个c++字符串中有多少相同的字符/数字
- C++有多少类型的循环
- 求出有多少个数字是完美平方,而sqrt()是L,R范围内的素数
- 保留对其他类的成员函数的引用
- 在条件变量中触发错误信号的频率是多少
- 函数的时间复杂度是多少?
- 指针保留字符串
- 是否有内置方法可以强制转换为不同的基础类型,但保留常量限定符?
- 如何让 GCC/Clang 在保留标识符上出错
- 必须为 C++20 协程帧保留多少内存?
- 对于四轴飞行器,PID中I控制器的理想值应该是多少
- 如何将一个窗口保留在另一个应用程序窗口的前面
- 使用 char 分隔符解析C++中的字符串,但将可重复的字符保留为每个解析的子字符串 (C++ STL) 中的分隔符
- C++,数组有多少个地址?
- std::basic_string构造函数如何事先知道要保留多少空间
- 如何确定为我的程序保留了多少虚拟内存