能否将std::ifstream::eof()作为std::ifstream::get()的有效分隔符?
用
std::ifstream::get时,能不能把file.eof()当成分隔符? 问题描述
已知std::ifstream::get有如下重载签名:
istream& get(char* s, streamsize n, char delim);
有人写出了这段代码,想用file.eof()作为分隔符读取整个文件:
const std::string_view arg1{argv[1]}; // 不拷贝 std::ifstream file(arg1.data(), std::ios::in | std::ios::ate); if (file) { auto file_size = file.tellg(); // 获取文件大小 std::unique_ptr<char[]> buf(new char[file_size]{}); file.seekg(0); // 移到文件开头 file.get(buf.get(), file_size, file.eof()); std::string_view sv{buf.get()}; // 不拷贝 }
代码运行起来没报错、没内存泄漏,但总感觉这么用file.eof()不太对。
结论:绝对不能这么用,这是严重的误用
核心问题
file.eof()返回的是bool值,而get的第三个参数要求是char类型。这里发生了隐式类型转换:true转成char是'\x01',false转成'\x00'。你实际设置的分隔符是这两个字符之一,根本不是“文件结束”的逻辑。
这段代码暂时能跑,只是刚好你的文件里没有'\x00'或'\x01',get才会一直读到缓冲区满或者真的文件末尾。一旦文件里出现这两个字符,读取会直接终止,导致你拿不到完整的文件内容——这是完全依赖未定义行为的巧合。
另外要明确:eof()的作用是检查是否已经触发了文件结束状态,它不是一个用来表示“文件结束”的字符标记,把它当成分隔符完全是对这个函数功能的误解。
正确的读取方式
要读取整个文件到缓冲区,用read()函数才是正确的选择,它专门用来读取指定字节数的内容:
file.read(buf.get(), file_size); // 读取后可以用gcount()确认实际读取的字节数,再构造string_view std::string_view sv{buf.get(), file.gcount()};
这种方式能保证你准确读取整个文件内容,不会因为意外字符提前终止,完全符合标准库的使用规范。
内容的提问来源于stack exchange,提问作者Chris Reid
相关产品推荐
相关产品推荐

