std :: string assign,clear和operator []

时间:2016-08-22 10:30:06

标签: c++ string clear

我正在观察字符串操作的一些奇怪行为。

前:

int main()
{
  std::string name("ABCDEFGHIJ");

  std::cout << "Hello, " << name << "!\n";
  name.clear();
  std::cout << "Hello, " << name << "!\n";
  name.assign("ABCDEF",6);
  std::cout << "Hello, " << name << "!\n";
  std::cout << "Hello, " << name[8] << "!\n";
}

输出:

Hello, ABCDEFGHIJ!
Hello, !
Hello, ABCDEF!
Hello, I!

string :: clear实际上没有清除,因为即使清除后我也能访问数据。根据文档,当我们访问超出范围的东西时,结果是未定义的。但在这里,我每次都得到相同的结果。 当我们调用clear或者opeartor []时,有人可以解释它在内存级别是如何工作的。

5 个答案:

答案 0 :(得分:8)

欢迎来到C ++的惊人吸引力,称为“未定义的行为”。

name包含六个字符的字符串“ABCDEF”时,name[8]会尝试访问字符串中不存在的成员,这是未定义的行为。

这意味着此操作的结果完全没有意义。

C ++标准没有定义访问字符串中不存在的成员字符的结果;因此未定义的行为。此操作的潜在结果可能是:

  1. 字符串中的某个先前值,位于给定位置。

  2. 一些垃圾,随机字符。

  3. 您的程序崩溃了。

  4. 还有别的。

  5. 每次执行程序时都会有不同的结果,从选项1到4中选择。

答案 1 :(得分:3)

  

name.assign( “ABCDEF”,6);

现在字符串的长度为6.因此,您可以合法地只访问元素0到5。

  

std :: cout&lt;&lt; “你好,”&lt;&lt; name [8]&lt;&lt; “\ N!”;

因此,这是未定义的行为。编译器可以随心所欲地做任何事情。不只是声明,而是整个程序,甚至前面的行!

此时,它返回了之前在该位置的角色。它可能已经返回任何其他东西,它可能已经崩溃,它可能完全跳过该声明,它可能已经跳过赋值和许多其他有趣的东西(包括让守护进程从你的鼻子中飞出来) !)。

而且我这样说是因为在各种情况下,所有这些行为(守护进程除外)都可以在野外实际观察到。

答案 2 :(得分:2)

正如其他人所说,访问它之外的std::string逻辑边界(即[0,size()],注意包含size())是未定义的行为,因此编译器可以做任何事情发生。

现在,你所看到的UB的特殊风味并不是特别出乎意料。

clear()只是将字符串的逻辑长度归零,但保留了它所使用的内存(标准实际需要它,而且如果没有这种行为,相当一些代码的工作速度会慢一些)。

鉴于没有充分的理由浪费时间将旧数据归零,通过访问超出界限的字符串,您可以看到之前在该索引处的内容。

如果你这样做可能会改变在shrink_to_fit()之后调用clear()方法,该方法要求字符串释放它保留的所有额外内存。

答案 3 :(得分:1)

我想添加其他答案,您可以使用std::string::at而不是operator[]

std::string::at执行边界检查,并在您尝试访问超出范围的元素时抛出std::out_of_range

答案 4 :(得分:0)

[我通过调试器运行你的代码。记下字符串的容量。它仍然是15.&#34;分配&#34;没有改变容量。所以你不会得到&#34;垃圾&#34;每个人都说的价值。您获得存储在同一位置的完全相同的数据。如上所述,字符串只是指向内存地址的指针。它将超过x个字节来访问该元素。 name [8]是一个常量值,它将转到完全相同的内存位置。 Here is a picture of the string in debugger