3

I am moving my project from Visual Studio 06 to 2010. While doing so, I have observed this behavior in my code. I have a Get string function that look like this:

string GetTheStr() 
{ 
        return strSomeStdString; 
} 

Then there is another function that call above get function like this:

const char* ptrStr = (char *)GetTheStr().c_str();

the value of string pointed by ptrStr is ""

above code was working fine in visual studio 06 but not on visual studio 2010.

Then I tried few experiments:

std::string str = GetTheStr(); // -> value inside str displayed correctly
const char* PtrCStr = str.c_str(); // -> value pointed by PtrCStr displayed correctly
const char* PtrData = str.data(); // -> value pointed by PtrData displayed correctly
const char* ptr = (char *)GetTheStr().c_str(); // -> value pointed by ptr NOT displayed correctly

I am wondering why last line didn't work. Can anyone please tell me why above behavior happen in visual studio 2010 but not on visual studio 06?

Thanks in advance :)

3
  • @MichaelAaronSafyan That should be an answer. Commented Aug 19, 2014 at 9:46
  • 1
    There is no need for the (char *) cast Commented Aug 19, 2014 at 9:53
  • Where does strSomeStdString actually come from? Commented Dec 2, 2014 at 19:29

2 Answers 2

9

What's happening in the invalid case is that GetTheStr() is returning a temporary, then c_str() is returning a reference to its internal data, then the temporary goes out of scope and suddenly you have a dangling reference to storage that is no longer valid. When you assign the returned value of GetTheStr() to a named variable, the variable is still alive and the result of its c_str() is still pointing to valid data.

Lifetimes of temporaries is something that varies between implementations. It is my understanding that a temporary lives for the entire statement (std::cout << GetTheStr().c_str() << endl; is technically valid to my understanding because the lifteime is required to last for the entire statement, but poorly written because it is relying on a very subtle aspect of lifetime); however, whether a temporary lives beyond that statement to the end of the scope or not is, to my understanding, implementation-defined. I'm probably going to be pilloried for this last paragraph (especially by people with more precise knowledge on the topic), but the short story is that well written code should be more explicit when the lifetime of an object needs to be extended; if you need to retain a reference to the internal data of an object, then it's always best to guarantee that there is a named variable referring to the object to ensure that the containing object's lifetime exceeds the lifetime of the usage of its internal data.

Sign up to request clarification or add additional context in comments.

3 Comments

the statement cout << GetTheStr().c_str() << endl is equivalent to operator<<(cout,GetTheStr().c_str()).operator<<(endl) from which you can see that the lifetime of the pointer is guaranteed for the function call of the first operator<<, unlike in the case where the pointer to the temporary is saved and passed
@DmitryLedentsov, even with the function call syntax, it's not immediately obvious that it should work (even though it is indeed valid). There's still this scary reference to data that will shortly be invalid. In an alternate universe, it would be just as logical for the programming language to say that the lifetime of the result of GetTheStr() ends before the function is invoked (though fortunately that's not the way things actually are). The defensive programmer in me always assumes the most malicious, non-compliant compiler and always assigns intermediate results to named variables.
yep, you're right, I've assumed too much. I guess we both should dig in the standard
7

in simple words

std::string str = GetTheStr(); // -> this is a copy of strSomeStdString
const char* PtrCStr = str.c_str(); // -> str is still alive, ok
const char* PtrData = str.data(); // -> str is still alive, ok
const char*ptr = (char *)GetTheStr().c_str(); // -> pointer to a temporary, bad

use the lifetime of str to keep the data "alive"

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.