如何在C++中泛化clearerr()以适配不同的流对象?
C++ 多次EOF结束的多行输入读取泛化实现方案
问题背景
开发C工具时需要两次读取多行用户输入,选择EOF(如Unix下^D、Windows下^Z)作为输入完成信号,使用while(std::getline(stream, string))的惯用法实现循环读取。
此时仅调用C流的clear()方法无法完全重置输入状态,底层关联的C标准IO文件流(如stdin)还需要调用clearerr()清除EOF标记,才能支持后续二次读取。
泛化适配方案
你已经确认逻辑上仅stdin需要执行clearerr()操作,因此只需要通过流的rdbuf()匹配判断,替换原代码中硬编码的clearerr(stdin)即可,适配任意std::istream类型输入。
修改后的核心代码
#include <istream> #include <vector> #include <string> #include <iostream> #include <cstdio> // 提供clearerr接口 std::istream& getlines (std::basic_istream<char> &theStream, std::vector<std::string> &stack) { std::ios::iostate current_mask (theStream.exceptions()); theStream.exceptions(std::ios::badbit); std::string _temp; while (theStream) { if (std::getline(theStream, _temp)) stack.push_back(_temp); } if (theStream.eof()) theStream.clear(theStream.rdstate() & (std::ios::failbit | std::ios::badbit)); if (theStream.fail() && !stack.size()) { throw std::ios::failure("No input received!"); } else if (theStream.fail() && stack.size()) { theStream.clear(theStream.rdstate() & std::ios::badbit); // 泛化修改:仅当输入流为std::cin时清除stdin的EOF标记 if (theStream.rdbuf() == std::cin.rdbuf()) { clearerr(stdin); } } theStream.exceptions(current_mask); return theStream; }
优化与兼容说明
- 移除了原代码中冗余的
std::string堆分配逻辑,改为栈分配即可满足需求,避免内存泄漏风险,性能更优 - 适配所有
std::istream类型输入:- 输入为
std::cin时,自动执行clearerr(stdin)清除底层C流的EOF标记,支持后续二次读取 - 输入为文件流、字符串流等非cin类型时,不执行额外操作,完全兼容原有逻辑
- 输入为
- 原错误拼写
recieved修正为标准拼写received
内容的提问来源于stack exchange,提问作者mavenor
相关产品推荐
相关产品推荐

