简体   繁体   中英

C++ strange behavior with string's c_str() function

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 :)

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.

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"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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