std:string 如何防止我不小心踩踏它的数据

How does std:string prevent me from carelessly stomping on its data?

本文关键字:数据 不小心 string 何防止 std      更新时间:2023-10-16

我有以下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 中。

相反,我得到这个输出:

字符串0

字符串1

字符串2

字符串0

字符串1

字符串2

String1aa

我对此有两个问题。首先,为什么增加 str1 的大小并向其添加字符负载不会流入 str2,即使它们应该在连续的内存块中?

其次,当我在调整 str1 大小并向其添加字符后第二次打印数组时,为什么它仍然打印原始 str1?我有一种感觉,这将与我的第一个问题的答案有关,但我不太明白这里发生了什么。

string 对象的数组是连续的,但实际的字符串数据存储在堆*上,因此字符串数据本身不是连续存储的。

* 实际上,给定一个使用"小字符串优化"的实现,数据是连续的,只要它足够小以适合,就存储在字符串对象中。"String0"对于我所知道的所有SSO实现来说都足够小。一旦数据增长到可以就地存储的内容,实现就会将其移动到堆上。

修改str1不会影响打印strArray[1]结果的原因是它们是没有关系的不同对象,只是您使用值初始化了strArray[1] str1 。这就像做:

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是常规类型。

正如 barnes53 指出的那样,string数组只存储string对象,并且可以简单地保存指向表示字符串的字符数组的指针。

第二个问题的答案是数组赋值是通过值而不是引用完成的,这意味着创建了字符串的副本。这就是为什么修改原始字符串对数组版本没有影响的原因。

数组是连续的,字符串不是。

你说str1.resize(200, 'a');对数组没有影响,因为数组包含str1过去不是referencevalue

因此,数组值不会溢出,因为数组中的值从未更改。