复制分配期间的c ++字符串容量更改

Posted

技术标签:

【中文标题】复制分配期间的c ++字符串容量更改【英文标题】:c++ string capacity change during copy assignment 【发布时间】:2014-06-25 03:03:33 【问题描述】:

在 C++ 标准中std:string 遵循指数增长策略,因此我认为在连接期间字符串的capacity() 将在必要时始终增加。但是,当我测试test.cpp 时,我发现在for 循环中,只有每两次capacity() 在赋值过程中才会缩回到length()

为什么这种行为不取决于字符串的长度,而是取决于我更改字符串的频率?是不是某种优化?

以下代码用g++ -std=c++11测试。

测试.cpp:

#include <iostream>  
int main(int argc, char **argv) 
  std::string s = "";
  for (int i = 1; i <= 1000; i++) 
    //s += "*";
    s = s + "*";
    std::cout << s.length() << " " << s.capacity() << std::endl;
  
  return 0;

输出将是这样的:

1 1
2 2
3 4
4 4
5 8
6 6    // why is capacity shrunk?
7 12
8 8    // and again?
9 16
10 10  // and again?
11 20
12 12  // and again?
13 24
14 14  // and again?
15 28
16 16  // and again?
17 32
...
996 996
997 1992
998 998  // and again?
999 1996
1000 1000  // and again?

【问题讨论】:

现在我想我不明白你的问题。是“为什么复制分配会减少容量?”如果是这样,答案不是很明显吗? @DavidSchwartz 我以前不知道这一点,但 abarnert 告诉我们“当从一个字符串复制分配到另一个字符串时,没有理由复制容量”?我的问题是,复制分配并不总是减少容量,而是每两次才这样做。 您可以简单地查看您的编译器实现std::string 的源代码,看看它为什么会这样做。 【参考方案1】:

当你这样做时:

s = s + "*";

您正在做两件不同的事情:创建一个新的临时字符串,将"*" 连接到内容s 的末尾,然后将该新字符串复制分配给s

缩小的不是+,而是=。当从一个字符串复制分配到另一个字符串时,没有理由复制容量,只复制实际使用的字节数。

您的注释掉的代码是这样做的:

s += "*";

... 只做一件事,将"*" 附加到s 的末尾。因此,“优化”无处可去(如果发生了,那将是一种悲观,违背了指数增长的全部目的)。

【讨论】:

"当从一个字符串复制分配到另一个字符串时,没有理由复制容量,只复制实际使用的字节。" - 这实际上并不能解释观察到的行为。对于 C++11,将移动分配分配给交换缓冲区是有意义的,因此分配给的对象具有临时的容量;对于 C++03,赋值 could 复制使用的字节,但是你不会期望容量会减少 - 这只会发生在使用引用计数的实现中,它会丢弃当前更大容量的缓冲区(即做你的“复制[的]实际使用的字节”。 无论如何 - +1 指出++= 之间的关键区别以及临时的重要性。干杯。【参考方案2】:

C++ 标准实际上并没有说明当字符串被移动、分配等时capacity() 会发生什么。这可能是一个缺陷。唯一的限制是可以从为操作指定的时间复杂度中推导出来的。

See here 用于关于向量的类似讨论。

【讨论】:

感谢您的链接!这很有帮助。

以上是关于复制分配期间的c ++字符串容量更改的主要内容,如果未能解决你的问题,请参考以下文章

C语言中string指令是啥?

复制C字符串的正确方法

C语言试题184之编写一个函数,从标准输入读取一个字符串,把字符串复制到动态内存分配的内存中,并返回该字符串的拷贝,这个函数不应该对读入字符串的长度作任何限制

C语言试题184之编写一个函数,从标准输入读取一个字符串,把字符串复制到动态内存分配的内存中,并返回该字符串的拷贝,这个函数不应该对读入字符串的长度作任何限制

结构中的字符数组 - 不兼容的分配? [复制]

C / C ++如何复制没有嵌套循环的多维char数组?