C ++数组的内存效率

时间:2018-02-27 22:21:19

标签: c++ arrays string size

在我脑干的某个地方,一个声音低语:

  

在C ++中,数组不需要比元素数量更多的内存   需要。

std::string str = "aabbcc"; 
std::array<std::string, 3> str_array = {"aa", "bb", "cc"}; 

因此,两者应该具有相同的大小,因为(与Java不同),没有单独的 size 字段或类似字段。但我还没有找到参考。

这是真的吗?在哪种情况下不是?

5 个答案:

答案 0 :(得分:4)

以任何语言存储字符串比您想象的更复杂。 C ++ std::string必须为内容提供连续的存储空间。除此之外,std::string可以容纳更多的东西,比如指针/迭代器到最后一个字符,其中的字符数等等。std::string::size必须是O(1),所以它必须存储更多信息而不仅仅是缓冲区。此外,大多数标准库实现提供SSO(小字符串优化)。启用S​​SO后,std::string会分配一个小缓冲区,以避免不必要的动态分配。您还可以保留比您需要的更多内存。可以说,你需要循环收集800-1000个字符。你可以这样做:

std::string str;
for(...)
    str += some_character;

但这会导致不必要的内存分配和解除分配。如果您可以估算要存储的字符数,则应该reserve内存。

std::string str;
str.reserve(1000);
for(...)
    str.push_back(some_character);

然后,你总是shrink_to_fit,以节省内存:

str.shrink_to_fit();

您还必须注意其他事项:

  • reserve会增加容量,但size保持不变。这意味着,std::string还必须存储(或能够计算)缓冲容量允许的字符数。
  • 字符串文字为空终止
  • std::basic_string::c_str必须返回以null结尾的字符数组,因此std::string也可能包含空终止符(不幸的是我不确定它是如何完成的)
  • 有更多的编码和字符集 - ASCII只是其中之一。 UTF-8和UTF-16编码的字符串可能需要使用少量存储元素来添加一个代码点,但这更复杂。

答案 1 :(得分:2)

  

在C ++中,数组不需要比需要的元素数量更多的内存。

这是事实。原始数组的大小等于它的大小,元素类型乘以元素数。所以

int array[10];

的大小为sizeof(int) * std::size(array)std::array是相同的,但允许填充

std::array<int, 10> array;

的大小为sizeof(int) * std::size(array) + P,其中P是一些整数填充量。

你的例子虽然不是一回事。 std::string是一个容器。它有自己的大小,它与它所包含的内容是分开的。因此,无论字符串中有多少个字符,sizeof(std::string)始终都是一样的。所以忽略短字符串优化

std::string str = "aabbcc"; 

sizeof(std::string)加上为底层c字符串分配的字符串。这与

的值不同
std::array<std::string, 3> str_array = {"aa", "bb", "cc"};

由于您现在拥有3 * sizeof(std::string)以及分配的每个字符串。

答案 2 :(得分:1)

  

因此,两者应具有相同的大小(例如6个字节),

不是正确的扣除。

std::string使用的内存(如果要调用其大小)至少包含一个指针和分配用于保存数据的内存。

分配用于保存数据的内存还可以包含保存终止空字符所需的空间。

鉴于

std::string s = "aabbcc";
std::string a = "aa";
std::string b = "bb";
std::string c = "cc";

mem(s) != mem(a) + mem(b) + mem(c)

答案 3 :(得分:1)

几乎每个字符串都可以包含以下信息:

  • 字符串的大小,即它包含的字符数。

  • 持有字符串字符的内存容量。

  • 字符串的值。

另外它也可能有:

  • 该值的分配器和引用计数的副本。

答案 4 :(得分:-3)

它们的大小不同。字符串以null结尾保存,为每个字符串提供额外的字节。