[英]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&
或扩展std::string
的生命周期,因为C ++ 11, 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,更好,但不必要)被执行。
顺便说一句,这个确切的问题甚至包含在“The C ++ Programming Language” 第 4版中!
在§10.3.4“临时对象”中,Stroustrup先生写道:
标准库字符串有一个成员
c_str()
(第36.3节),它返回一个C样式指针,指向一个以零结尾的字符数组(§2.2.5,§43.4)。 此外,operator+
被定义为表示字符串连接。 这些是字符串的有用工具。 但是,它们可能会导致模糊的问题。 例如: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_str()
返回的C样式字符串被分配为保存s1+s2
的临时对象的一部分,并且在该临时性被销毁之后不保证该存储存在。 因此,cs
指向解除分配的存储。 输出操作cout<<cs
可能会按预期工作,但这将是纯粹的运气。 编译器可以检测并警告此问题的许多变体。if
-statement的问题有点微妙。 条件将按预期工作,因为创建临时保持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();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.