2014-04-11 117 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()正在执行其打印作业。

相关问题