2014-04-11 167 views
4

給出一個簡單的文件加載功能,爲什麼c_str()爲兩個不同的字符串返回相同的值?

std::string load_file(const std::string &filename) { 
    std::ifstream  file(filename); 
    std::string  line; 
    std::stringstream stream; 
    while (std::getline(file, line)) { 
     stream << line << "\n"; 
    } 
    return stream.str(); 
} 

爲什麼以下打印的another_file兩倍的內容是什麼?

const char *some_file = load_file("some_file").c_str(); 
const char *another_file = load_file("another_file").c_str(); 
printf("%s", some_file); 
printf("%s", another_file); 
+0

我不認爲在返回值上調用c_str()而不顯式存儲字符串是安全的。比較some_file和another_file的指針值,我認爲它們是一樣的。 – Ryp

+0

ifstream在C++ 11中也沒有使用std :: string。 https://stackoverflow.com/a/37542/2591612 – Brian

回答

14

代碼壞了。您正在對立即銷燬的臨時對象調用c_str()。這意味着c_str()返回的值無效。

您需要確保std::string對象返回生存,至少只要您保留由c_str()調用返回的指針。例如:

std::string some_file = load_file("some_file"); 
std::string another_file = load_file("another_file"); 
printf("%s", some_file.c_str()); 
printf("%s", another_file.c_str()); 
3

在線路是這樣的:

const char *some_file = load_file("some_file").c_str(); 

load_file()返回臨時std::string,然後.c_str()上調用此暫時的。

當臨時存活時,由.c_str()返回的指針指向一些有意義的字符串。但是當臨時的「蒸發」(在分號處)時,那麼同樣的指針指向垃圾。

「垃圾」可能與先前調用load_file()返回的字符串相同,因此您的效果是兩個原始指針都指向同一個字符串。 但這只是一個巧合。
而你的代碼有一個錯誤。

字符串std::string這樣發明是爲了簡化C++程序員的生活而不是使用原始C字符串指針。所以,如果你想在C++中安全地管理字符串,只需使用std::string即可。

考慮在具有C函數(包括printf())的邊界處使用.c_str()只是

所以,你可以重構你的代碼是這樣的:

// load_file() returns a std::string, so just keep using std::string. 
// Note that returning std::string is efficient thanks to RVO/NRVO 
// and C++11 move semantics. 
std::string some_file = load_file("some_file"); 

// Idem for this: 
std::string another_file = load_file("another_file"); 

// Convert from std::string to raw C string pointers at the C boundary 
printf("%s\n", some_file.c_str()); 
printf("%s\n", another_file.c_str()); 

即使是像這樣的代碼將很好地工作:

printf("%s\n", load_file("some_file").c_str()); 
printf("%s\n", load_file("another_file").c_str()); 

事實上,注意,在這種情況下,即使你是使用臨時(即load_file()返回的字符串不復制到的變量名爲std::string),臨時在printf()調用期間有效,所以原始指針返回b y .c_str()指向有效的字符串,而printf()正在執行其打印作業。

相關問題