("Some extra info \n" + errorMessage()) 是一个临时 std::string。这意味着,语句完成后,它的生命周期就结束了。
cout << ("Some extra info \n" + errorMessage()).c_str() << endl
有效,因为此时std::cout 使用std::string,它的生命周期尚未结束。
<< message
part 是未定义的行为。纯粹是运气好。
要解决此问题,您需要使用 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();
但是,如果编译器不做一些Return Value Optimization,这将导致构造函数和复制构造函数(非常糟糕 ) 或移动构造函数(>= C++11,更好,但不必要)被执行。
顺便说一句,这个确切的问题甚至在“C++ 编程语言”第 4th 版中都有介绍!
在第 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 指向 deallocated
贮存。输出操作cout<<cs 可能会按预期工作,但是
那将是纯粹的运气。编译器可以检测并警告
这个问题的许多变种。
if-statement 的问题有点微妙。这
条件将按预期工作,因为其中的完整表达式
创建的临时持有s2+s3 是条件本身。
但是,该临时文件在受控语句之前被销毁
已输入,因此无法保证对 cs 的任何使用都有效。
所以,不要担心你的 C++ 技能。甚至 C++ 圣经也解释了这一点。 ;-)