在关于优化和代码风格的 C++ 问题中,有几个答案在优化std::string. 在这种情况下,SSO 是什么意思?
std::string
显然不是“单点登录”。也许是“共享字符串优化”?
对自动变量的操作(“从堆栈”,这是您在不调用malloc/的情况下创建的变量new)通常比那些涉及自由存储(“堆”,这是使用创建的变量)快得多new。但是,自动数组的大小在编译时是固定的,但来自自由存储的数组的大小不是。此外,堆栈大小是有限的(通常为几个 MiB),而免费存储仅受系统内存的限制。
malloc
new
SSO 是短/小字符串优化。Astd::string通常将字符串存储为指向空闲存储(“堆”)的指针,这提供了与调用new char [size]. 这可以防止非常大的字符串的堆栈溢出,但它可能会更慢,尤其是复制操作。作为一种优化,许多实现std::string创建一个小的自动数组,比如char [20]. 如果您有一个 20 个字符或更小的字符串(在此示例中,实际大小会有所不同),它将直接将其存储在该数组中。这完全避免了调用的需要new,从而加快了速度。
new char [size]
char [20]
编辑:
我没想到这个答案会如此受欢迎,但既然如此,让我给出一个更现实的实现,但需要注意的是,我从未真正“在野外”阅读过任何 SSO 的实现。
a 至少std::string需要存储以下信息:
大小可以存储为 astd::string::size_type或指向末尾的指针。唯一的区别是您是否希望在用户调用时必须减去两个指针,或者在用户调用时向指针size添加 a 。容量也可以以任何一种方式存储。size_type``end
std::string::size_type
size
size_type``end
首先,根据我上面概述的内容考虑简单的实现:
class string { public: // all 83 member functions private: std::unique_ptr<char[]> m_data; size_type m_size; size_type m_capacity; std::array<char, 16> m_sso; };
对于 64 位系统,这通常意味着std::string每个字符串有 24 个字节的“开销”,另外还有 16 个字节用于 SSO 缓冲区(由于填充要求,此处选择 16 个而不是 20 个)。存储这三个数据成员加上一个本地字符数组是没有意义的,就像在我的简化示例中一样。如果m_size <= 16,那么我会将所有数据放入m_sso,所以我已经知道容量并且我不需要指向数据的指针。如果m_size > 16,那么我不需要m_sso。在我需要所有这些的地方绝对没有重叠。一个不浪费空间的更智能的解决方案看起来更像这样(未经测试,仅用于示例目的):
m_size <= 16
m_sso
m_size > 16
class string { public: // all 83 member functions private: size_type m_size; union { class { // This is probably better designed as an array-like class std::unique_ptr<char[]> m_data; size_type m_capacity; } m_large; std::array<char, sizeof(m_large)> m_small; }; };
我假设大多数实现看起来更像这样。