繁体   English   中英

使用const char *的奇怪的std :: 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&或扩展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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM