views:

288

answers:

4

I have a function which shall return a char*. Since I have to concatenate some strings, I wrote the following line:

std::string other_text;
// ...
return ("text" + other_text).c_str();

I know that I could avoid the question naming the string I want to return. I just want to take the chance to make a more general question: is it safe to call methods of temporary variables? is it standard compliant?

+7  A: 

It is safe to call methods of temporary variables, but not safe to return a char* of a temporary variable for later use.

This char* points to a buffer that will be freed soon. Once it is freed you will have a pointer to an invalid region in memory.

Instead please return an std::string object.

Brian R. Bondy
It is freed as the function returns, to be specific, according to section 12.2 of the standard. Once the calling statement gets the pointer, it's invalid.
David Thornley
Thanks. As for the "return problem" you (all of you) are right of course. I'm shocked because generally I don't make mistakes like that. Anyway thanks for pointing that up, as well.
happy_emi
+4  A: 

You are allowed to call methods on temporaries, however you have to be careful about object lifetimes -- in particular, if you have a function that returns c_str() called on a temporary std::string, that string object will be destroyed when the function returns.

Your code above suffers from this problem.

j_random_hacker
In the standard, section 21.3.7.1 lists the required operator+()s, and operator+(const char *, string) is included. If the original doesn't compile, it's a compiler or library bug.
David Thornley
@david - what has that to do with this reply?
anon
It'll compile - and then crash at run-time (depending on how the char* is used).
Douglas Leeder
@David: Thanks, I double-checked the standard and sure enough there it was! I've gotten rid of that section of the reply now.
j_random_hacker
@Neil, Douglas: In the initial version of my post I claimed that the string literal would need to be the 2nd argument to operator+(), but I was wrong -- I've since retracted that part. That's what David was referring to.
j_random_hacker
+3  A: 

The C-string returned by calling c_str() on the temporary will be valid until the next call to c_str() on the temporary, which can never happen. The temporary itself hangs around to the end of the full expression it is part of (the return statement).

If you were returning a std::string, everything would be hunkydory, as the string's copy constructor would be invoked in the return to take a copy. If you return a char *, then all bets are off, as the value you are returning will be disposed of when the function exits. This doesn't have anything specifically to do with the temporary, it is a general problem when returning char * - prefer to return std::strings instead.

anon
+1. And even more generally, it's a general problem when returning a pointer or reference to something, or a part of something, that's about to go out of scope.
j_random_hacker
What does the next call to c_str() have to do with the lifetime of the char* returned by c_str()? That pointer will be valid until the next next call to a non-const member function of the string object, which in this case is the dtor on the temporary called when the return is executed.
Michael Burr
@Michael: Actually that's a good point.
j_random_hacker
A: 

A generated pointer will be good for as long as the temporary is still around, which is normally until the end of the expression. The exceptions are when a temporary is used in an initializer (in which case it lasts until the initialization is over), or when bound to a reference. A temporary in a function return statement lasts until the function exits (unless bound to a reference). Once the temporary lifetime is over, the temporary is destroyed. In this case, it means that the string destructor runs, and therefore the memory for the characters is freed. In other words, once the value is returned, it's guaranteed invalid.

You could pass the string itself back, returning it as a const reference. You could copy the .c_str() to newly allocated memory, and pass that back (as a pointer or smart pointer). Either of those would work.

The lifetime of temporaries is covered in section 12.2 of the C++ standard. According to the standard, you're returning a pointer to freed memory.

David Thornley