【问题标题】:Does the std::string copy constructor add null character at the end by itself?std::string 复制构造函数是否自己在末尾添加空字符?
【发布时间】:2014-06-18 04:25:21
【问题描述】:

首先我在做,

#include <iostream>
#include <string>

void foo (std::string s) {
    std::cout << s << std::endl;
}

int main () {
    char st[] = "0";
    st[1] = '[';
    std::string s (st);
    std::cout << s << std::endl;
    return 0;
}

当我使用流插入运算符发送到流对象cout 时,它显示垃圾(猜测这是正常行为)。

然后我通过按值传递给函数foo 进行检查。 我现在正在做这样的事情。

    foo (s);

    // after calling foo () value printed by the
    // std::cout is changed. it takes care of NULL character ('\0')
    std::cout << s << std::endl;

0[ 之后不再显示垃圾信息。为什么?

我的问题是, 我按值传递了foo () 中的字符串。在运行 foo () 的主体之前运行一个复制构造函数。但仍然没有意义。这个copyctor如何通过值改变从main ()传递的参数?

提前致谢。

【问题讨论】:

  • 未定义的行为,因为您破坏了字符串。
  • 在调试器中打开你的程序,看看st指向什么。那你就知道了。
  • 当你删除它时,我正在回答你关于 ISR 的问题!

标签: c++ function stl iostream


【解决方案1】:
char st[] = "0";

小测验:st 有多大?

答案:两个chars 一个用于"0",一个用于空终止符。

然后你去覆盖空终止符:

st[1] = '[';

...并尝试在此基础上构建string

std::string s (st);

这里调用了带有const char*string 构造函数,它的工作方式是查找空终止符。既然你把它吹走了,它就会跑到st 的末尾。跑过st 的末尾会引发未定义的行为,这就是您看到垃圾的原因。

请务必注意,未定义行为意味着任何事情都可能发生。这里的“任何事情”包括“正是我想要发生的事情”。你不一定会得到垃圾输出,或者你的程序会崩溃。试图解释为什么 UB 会以这种方式或那样表现自己是一种不合理的努力。

【讨论】:

  • 重要的是要注意:未定义的行为不必是一致的。
  • 那为什么我传给foo()时不显示垃圾? cout 打印到空。对吗?
  • @Fahad:也许第一条垃圾恰好是'\0'。你试图为不合理的事情合理化。
  • @Fahad:未定义的行为意味着任何事情都可能发生——其中包括您期望发生的事情。
  • @JohnDibling:我们可以根据计算机的工作方式做出合理的假设,只要我们附上免责声明,这只是一个猜测。但是,对于 C 字符串,没有什么好争论的。
【解决方案2】:

人们在告诉你未定义的行为。这很好,但你已经知道了。

实际上,这里的关键是您的第一个“垃圾”字符本身很可能是 '\0' 字符,在这种情况下,您将看不到任何其他字节。

您不能仅仅假设您将看到至少 20 个任意字符,因为您的代码的一个完全合理的结果是您看到 0 个任意字符。

简而言之,您试图将不合理的事情合理化;住手!

【讨论】:

  • 真的是一个词吗?
  • @JohnDibling:现在是
【解决方案3】:

这两行之后:

char st[] = "0";
st[1] = '[';

st 不是以空字符结尾的字符串。 std::string(char const*) 需要一个以空字符结尾的字符串。由于std:string 的构造函数的输入不符合该标准,因此您正在进入未定义的行为领域。之后任何事情都可能发生。

【讨论】:

  • 我是故意的。传递给函数 foo() 后,为什么不显示垃圾?问题是:为什么函数 foo 改变了从 main() 传递的对象。
【解决方案4】:

这一行:

char st[] = "0";

使编译器分配一个 2 字节数组固定大小的数组并用“0\0”(ASCII 0 后跟一个空字符)填充它。这一行

st[1] = '[';

然后将 '[' 分配给 NULL 先前占用的位置,从而破坏字符串的空终止。那么这一行

std::string s (st);

将从st 的开头开始并继续将字符复制到s 中,直到它在内存中的某处找到一个空值。这就是你看到垃圾的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-29
    • 2012-05-08
    • 2011-06-06
    相关资源
    最近更新 更多