我有以下C代码:
#include <string> #include <iostream> int main(int argc,char** argv) { int size; std::string strArray[3]; std::string str0 = "String 0"; std::string str1 = "String 1"; std::string str2 = "String 2"; strArray[0] = str0; strArray[1] = str1; strArray[2] = str2; for (int i = 0; i < 3; i++) { std::cout << strArray[i] << std::endl; } str1.resize(200,'a'); for (int i = 0; i < 3; i++) { std::cout << strArray[i] << std::endl; } std::cout << str1 << std::endl; std::cin.get(); return 0; }
这里的想法是我有一个数组,它是一个连续的内存块,其中每个成员都是一个std :: string,它是可变的,因此大小可变.我期望这段代码能够破解,因为我调整str1的大小来占用比原来更多的空间,因此“溢出”到str2中.
相反,我得到这个输出:
String0
String1中
字符串2
String0
String1中
字符串2
String1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa …
我有两个问题.首先,如何增加str1的大小并向其添加大量字符不会流入str2,即使它们应该位于连续的内存块中?
第二,为什么在调整str1大小后第二次打印数组并向其添加字符时,它仍会打印原始的str1?
我有一种感觉,这将与我的第一个问题的答案有关,但我不能完全看到这里发生了什么.
解决方法
字符串对象数组是连续的,但实际的字符串数据存储在堆*上,因此字符串数据本身不会连续存储.
*实际上给定一个使用“小字符串优化”的实现,数据是连续的,只要它足够小就可以存储在字符串对象中. ‘String0’足够小,适用于我所知道的所有SSO实现.一旦数据增长超过可以就地存储的内容,实现就会将其移动到堆上.
修改str1不会影响打印strArray [1]的结果的原因是它们是没有关系的不同对象,除了用str1的值初始化strArray [1].这就像做:
int intArray[3]; int int0 = 0; int int1 = 1; int int2 = 2; intArray[0] = int0; intArray[1] = int1; intArray[2] = int2; int1 = 10000000; // does not modify intArray[1]
这里的想法是C中对象的通常行为与您在其他语言中可能熟悉的“原始类型”或“值类型”相同.可以在C中实现其他行为,但std :: string是常规类型.