是否保证std :: string不自发地返回内存?

时间:2018-09-25 10:13:36

标签: c++ language-lawyer heap-memory stdstring

标准是否保证std::string如果从较小的字符串中重新分配,将不会自发地返还分配的内存?

换句话说:

std::string str = "Some quite long string, which needs a lot of memory";
str = "";
str = "A new quite long but smaller string"; // Guaranteed to not result in a heap allocation?

我问,因为我依靠它来避免堆碎片。

4 个答案:

答案 0 :(得分:35)

不做任何保证。

[string.cons]/36定义了根据移动分配将const char*分配给std::string的定义,

  

[string.cons]/32

basic_string& operator=(basic_string&& str)  noexcept(/*...*/)
     

效果:Move分配作为序列容器,但迭代器,指针和引用可能无效。

这表明,委员会让执行程序在无效操作和更为保守的操作之间自由选择。为了使事情更加清晰:

  

[basic.string]/4

     

引用basic_­string序列的元素的引用,指针和迭代器可能会由于以下basic_­string对象的使用而失效:

     
      
  • (4.1)作为任何标准库函数的参数,并以非常量basic_­string的引用作为参数。
  •   
  • (4.2)调用非常量成员函数,但operator[]atdatafrontbackbeginrbeginendrend
  •   

  

我问,因为我依靠它来避免堆碎片。

std::string将分配器作为模板参数。如果您真的担心可能出现的堆碎片,则可以编写自己的堆碎片,并通过一些启发式方法来制定适合您需求的分配策略。

在实践中,我所知道的大多数实现都不会在您遇到问题时重新分配内存。可以通过测试和/或检查您的实施文档以及最终的源代码来进行检查。

答案 1 :(得分:13)

CPP reference指出分配给指向字符的指针

  

将内容替换为s所指向的以空终止的字符串,就像* this = basic_string(s)一样,这涉及对Traits :: length(s)的调用。

这个“好像”实际上可以归结为一个右值赋值,因此很可能出现以下情况:

  1. 创建了一个新的临时字符串。
  2. 字符串通过分配给右值引用来窃取其内容。

答案 2 :(得分:4)

  

如果从较小的字符串中重新分配了std :: string,是否可以保证std :: string不会自发地放弃分配的内存?

不管实际答案是什么(“不,不保证”),您都应遵循以下原则:如果不清楚是否必须这样做,则不要以为是

在您的特定情况下-如果您想严格控制堆的行为,甚至可能根本不想使用std::string(取决于情况)。而且您可能不想使用默认分配器(可能再次);并且您可能想memoize strings;等。您绝对应该做的是减少假设,进行可能的测量,并进行明确的设计以确保满足您的需求。

答案 3 :(得分:2)

如果您的字符串很短(最多15或22个字节,具体取决于编译器/标准库),并且您正在C ++ 11或更高版本的模式下使用相对较新的编译器,那么您很可能会受益于{ {3}}(SSO)。在这种情况下,字符串内容不会在堆上单独分配。

此链接还包含有关常见实现和分配策略的许多详细信息。

但是,示例中的两个字符串对于SSO来说都太长了。