("Some extra info \n" + errorMessage())
is a temporary std::string
. That means, after the statement is finished, it's lifetime has ended.
cout << ("Some extra info \n" + errorMessage()).c_str() << endl
works because at the point std::cout
uses the std::string
its lifetime hasn't ended yet. The
<< message
part is undefined behavior, though. Sheer luck it works.
To fix the problem, you need to extend the std::string
's lifetime with either a const std::string&
or, since C++11, a std::string&&
:
const std::string& str_const_ref = "Some extra info \n" + errorMessage();
std::string&& str_rvalue = "Some extra info \n" + errorMessage();
Now you can operate on them as you want to.
Another way is to
std::string str = "Some extra info \n" + errorMessage();
However, if the compiler doesn't do some Return Value Optimization, this will lead to a constructor and a copy constructor (< C++11, very bad) or move constructor (>= C++11, better, but unnecessary) getting executed.
BTW, this exact issue is even covered in "The C++ Programming Language" 4th Edition!
In §10.3.4 "Temporary Objects", Mr Stroustrup writes:
The standard-library string has a member c_str()
(§36.3) that returns a C-style pointer to a zero-terminated array of characters
(§2.2.5, §43.4). Also, the operator +
is defined to mean string
concatenation. These are useful facilities for strings. However, in
combination they can cause obscure problems. For example:
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
}
}
[...] A temporary string object is created to hold s1+s2
. Next, a pointer
to a C-style string is extracted from that object. Then – at the end of
the expression – the temporary object is deleted. However, the C-
style string returned by c_str()
was allocated as part of the temporary
object holding s1+s2
, and that storage is not guaranteed to exist after
that temporary is destroyed. Consequently, cs
points to deallocated
storage. The output operation cout<<cs
might work as expected, but
that would be sheer luck. A compiler can detect and warn against
many variants of this problem.
The problem with the if
-statement is a bit more subtle. The
condition will work as expected because the full expression in which
the temporary holding s2+s3
is created is the condition itself.
However, that temporary is destroyed before the controlled statement
is entered, so any use of cs
there is not guaranteed to work.
So, do not worry about your C++ skills. Even the C++ bible explains it. ;-)