猿问

libc ++中短字符串优化的机制是什么?

libc ++中短字符串优化的机制是什么?

我想更详细地了解它在实践中是如何工作的,特别是在libc ++实现中:

  • 为了符合SSO资格,字符串有多短?这取决于目标架构吗?

  • 在访问字符串数据时,实现如何区分短字符串和长字符串?它m_size <= 16是一个简单的,还是一个标志,是其他成员变量的一部分?(我想这m_size或其中的一部分也可能用于存储字符串数据)。

我专门针对libc ++问了这个问题,因为我知道它使用SSO,甚至在libc ++主页上也提到过。

以下是查看来源后的一些观察结果:

libc ++可以使用两个稍微不同的字符串类内存布局进行编译,这由_LIBCPP_ALTERNATE_STRING_LAYOUT标志控制。这两种布局还区分了little-endian和big-endian机器,这些机器总共留下了4种不同的变体。我将在下面的内容中假设“正常”布局和小端。

假设进一步size_type是4个字节并且value_type是1个字节,这就是字符串的前4个字节在内存中的样子:

// short string: (s)ize and 3 bytes of char (d)atasssssss0;dddddddd;dddddddd;dddddddd       ^- is_long = 0// long string: (c)apacityccccccc1;cccccccc;cccccccc;cccccccc       ^- is_long = 1

由于短字符串的大小在高7位,因此在访问它时需要移位:

size_type __get_short_size() const {
    return __r_.first().__s.__size_ >> 1;}

类似地,长字符串容量的getter和setter用于__long_mask解决这个问题is_long

我仍在寻找我的第一个问题的答案,即__min_cap短字符串的容量对不同的架构有什么价值?



杨__羊羊
浏览 643回答 2
2回答

冉冉说

在libc中++实现有点复杂,我会忽略它的替代性设计,并假设小端计算机:template <...>class basic_string {/* many many things */&nbsp; &nbsp; struct __long&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; size_type __cap_;&nbsp; &nbsp; &nbsp; &nbsp; size_type __size_;&nbsp; &nbsp; &nbsp; &nbsp; pointer&nbsp; &nbsp;__data_;&nbsp; &nbsp; };&nbsp; &nbsp; enum {__short_mask = 0x01};&nbsp; &nbsp; enum {__long_mask&nbsp; = 0x1ul};&nbsp; &nbsp; enum {__min_cap = (sizeof(__long) - 1)/sizeof(value_type) > 2 ?&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (sizeof(__long) - 1)/sizeof(value_type) : 2};&nbsp; &nbsp; struct __short&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; union&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; unsigned char __size_;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value_type __lx;&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; value_type __data_[__min_cap];&nbsp; &nbsp; };&nbsp; &nbsp; union __ulx{__long __lx; __short __lxx;};&nbsp; &nbsp; enum {__n_words = sizeof(__ulx) / sizeof(size_type)};&nbsp; &nbsp; struct __raw&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; size_type __words[__n_words];&nbsp; &nbsp; };&nbsp; &nbsp; struct __rep&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; union&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; __long&nbsp; __l;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; __short __s;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; __raw&nbsp; &nbsp;__r;&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; };&nbsp; &nbsp; __compressed_pair<__rep, allocator_type> __r_;}; // basic_string注意:__compressed_pair基本上是针对空基优化而优化的一对,又称template <T1, T2> struct __compressed_pair: T1, T2 {};; 对于所有意图和目的,你可以认为它是一个常规对。它的重要性刚刚出现,因为它std::allocator是无国籍的,因此是空的。好的,这是相当原始的,所以让我们检查一下这些机制!在内部,许多函数将调用__get_pointer()自己调用__is_long以确定字符串是否使用__long或__short表示:bool __is_long() const _NOEXCEPT&nbsp; &nbsp; { return bool(__r_.first().__s.__size_ & __short_mask); }// __r_.first() -> __rep const&//&nbsp; &nbsp; &nbsp;.__s&nbsp; &nbsp; &nbsp;-> __short const&//&nbsp; &nbsp; &nbsp;.__size_ -> unsigned char说实话,我不太确定这是标准C ++(我知道最初的子序列规定,union但不知道它是如何与匿名联合和别名一起抛出的),但是允许标准库利用定义的实现无论如何。
随时随地看视频慕课网APP
我要回答