奇怪的标准::带有常量字符*的cout行为
Strange std::cout behaviour with const char*
>我有一个返回字符串以显示为错误消息的方法。根据此错误在程序中发生的位置,我可能会在显示错误消息之前向错误消息添加更多解释。
string errorMessage() {
return "this is an error";
}
// somewhere in the program...
const char* message = ("Some extra info n" + errorMessage()).c_str();
cout << message << endl;
(我将消息存储为 const char*,因为我实际上会将此错误提供给另一个接受 const char* 参数的方法(
此时,它会输出垃圾(控制台上不可打印的字符(。
所以我玩了一下,发现如果我这样做:
// somewhere in the program...
const char* message = ("Some extra info n" + errorMessage()).c_str();
cout << ("Some extra info n" + errorMessage()).c_str() << endl << message << endl;
然后它会正确显示消息两次。
为什么向cout
提供额外的参数会导致它按我的预期工作?
("Some extra info n" + errorMessage())
是一个临时std::string
。这意味着,语句完成后,其生命周期已结束。
cout << ("Some extra info n" + errorMessage()).c_str() << endl
之所以有效,是因为在std::cout
使用该std::string
其生命周期尚未结束时。这
<< message
但是,部分是未定义的行为。纯粹是运气好。
要解决此问题,您需要使用const std::string&
或自 C++11 起延长std::string
的生命周期std::string&&
:
const std::string& str_const_ref = "Some extra info n" + errorMessage();
std::string&& str_rvalue = "Some extra info n" + errorMessage();
现在,您可以根据需要对它们进行操作。
另一种方法是
std::string str = "Some extra info n" + errorMessage();
但是,如果编译器不执行一些返回值优化,这将导致构造函数和复制构造函数(<C++11,>非常糟糕(或移动构造函数(>= C++11,更好,但不必要的(被执行。
顺便说一句,这个确切的问题甚至在"C++编程语言"第 4 版中都有涉及!
在§10.3.4"临时对象"中,Stroustrup先生写道:
标准库字符串具有一个成员
c_str()
(§36.3(,该成员返回指向以零结尾的字符数组的 C 样式指针 (§2.2.5, §43.4(。此外,运算符+
定义为表示字符串 串联。这些是字符串的有用工具。然而,在 组合它们可能会导致模糊的问题。例如:void f(string& s1, string& s2, string& s3) { const char* cs = (s1+s2).c_str(); cout << cs; if (strlen(cs=(s2+s3).c_str())<8 && cs[0]=='a') { // cs used here } }
[...]创建一个临时字符串对象来保存
s1+s2
。接下来,指针 从该对象中提取 C 样式字符串。然后 - 在结束时 表达式 – 删除临时对象。然而,C-c_str()
返回的样式字符串作为临时的一部分进行分配 对象保存s1+s2
,并且该存储不保证在之后存在 那个临时被摧毁了。因此,cs
点要解除分配 存储。输出操作cout<<cs
可能按预期工作,但 那纯粹是运气。编译器可以检测并警告 此问题的许多变体。if
语句的问题有点微妙。这 条件将按预期工作,因为其中的完整表达式 创建的临时持有s2+s3
是条件本身。 但是,该临时在受控语句之前被销毁 输入,因此任何使用cs
都不保证有效。
所以,不要担心你的C++技能。甚至C++圣经也解释了它。;-)
const char* message = ("Some extra info n" + errorMessage()).c_str();
cout << message << endl;
errorMessage()
返回一个临时std::string
对象
与"Some extra info n" + errorMessage()
连接将创建另一个临时对象。
获取它c_str返回指向其内部缓冲区(而不是副本(的指针。
然后删除临时对象,指针无效。
其他一切都是未定义的。它可能会提供正确的输出、崩溃或执行其他任何操作。
问题就在这里:
const char* message = ("Some extra info n" + errorMessage()).c_str();
errorMessage(( 将返回一个临时的 std::string,在下一行运行之前,该字符串将超出范围。
我建议这样做:
std::string message = "Some extra info n" + errorMessage();
然后,当您需要传递指向基础缓冲区的指针时,可以使用:
message.c_str();
- 为什么strlen(s)与s的大小不同,为什么cout-char显示的是字符而不是数字
- 在 c++ 中以十六进制格式打印无符号字符(BYTE).使用 std::cout
- 为什么 cout() 要砍掉多个字符?
- 长度为 20 的 Cout'ing 数组输出 23 个字符
- Cout 在循环访问常量字符时提供垃圾输出
- cout 打印的字符 [] 包含的字符数超过设置长度
- & 字符在重载 std::cout 中的功能是什么?
- 循环中的 Cout 不会按定义的字符逐个打印字符
- NULL字符未出现在COUT中
- Cout删除了(未签名的字符)指针,给了我意外的结果
- 使用CIN和COUT时,字符变量无法正确打印
- 对于字符d,我在执行cout <<&d时得到奇怪的输出
- 托架返回,导致COUT覆盖字符并打印出订单
- cout.put() 是否推荐使用 cout<< 打印字符
- 模板字符/wchar_t,字符串/w字符串,cout/wcout,regexp / wregex(或任何可能的解决方法)
- 来自字符的 cout exe 文件内容
- 正在将最后一个字符发送到std::cout
- 如何在cout中插入N个字符
- 为什么将字符指针流式传输到 cout 不打印地址
- C++中的希伯来字符(cout<<char<<char;)