我可以让std::string使用更少的内存吗

Can I make std::string use less memory?

本文关键字:内存 std string 我可以      更新时间:2023-10-16

在开始之前,我需要说明我的应用程序使用了大量字符串,这些字符串平均来说非常小,并且在创建后不会更改。

在VisualStudio2010中,我注意到std::string的容量至少为30。即使我写std::string str = "test";,str的容量也是30。函数str.shrink_to_fit()对此没有任何作用,尽管std::vector存在一个同名函数,并且按预期工作,即降低容量,使容量==大小。

  1. 为什么std::string::shrink_to_fit()不能按预期工作
  2. 如何确保字符串分配的内存最少
  1. 您的std::string实现很可能使用某种形式的短字符串优化,从而使较小字符串的大小固定,而对shrink_to_fit没有影响。注意,shrink_to_fit对于实现是不绑定的,所以这实际上是一致的
  2. 您可以使用vector<char>来获得更精确的内存管理,但会丢失std::string的一些附加功能。您也可以编写自己的string包装器,该包装器在内部使用vector

std::string::shrink_to_fit()什么都不做的一个原因是标准不要求它

备注: shrink_to_fit是将capacity()缩减为size()的非绑定请求。[注意:该请求是不绑定的,以允许实现特定优化的自由度。--结束注释]

如果你想确保字符串收缩,那么你可以像一样使用swap()技巧

std::string(string_to_shrink).swap(string_to_shrink)

这可能不起作用的另一个原因是std::string的实现者被允许实现短字符串优化,因此您的实现中的最小大小总是30。

正如其他人所指出的,您观察到的是SSO(短字符串优化)的结果。

你能做些什么取决于使用模式:

  • 如果你的字符串是一个大字符串的一部分,这是典型的解析,你可以使用std::experimental::string_view、GSL string_span、Google的StringPiece、LLVM的StringRef等类,它们本身不存储数据,只引用其他字符串的一段,同时提供类似于std::string的接口。

  • 如果有相同字符串的多个副本(尤其是长字符串),则使用CoW(写时复制)字符串可能是有意义的,其中副本使用引用计数器机制共享相同的缓冲区,直到被修改为止。(但要注意缺点)

  • 如果字符串很短(只有几个字符),那么编写自己的专用类可能是有意义的,这与Andrzej 的Handling short codes一致

无论你选择什么情况,重要的是建立良好的基准程序,以清楚地看到你得到了什么效果(如果有的话)。

Upd:在重读了问题的引言之后,我认为第三种方法对你来说是最好的。

如果您在应用程序中使用了很多小字符串,那么您可能需要查看fbstring(https://github.com/facebook/folly/blob/master/folly/docs/FBString.md)。