重载>>运算符读取fstream对象时出现重复读取的问题排查
问题:从文件读取Student对象到vector时的异常输出
场景与代码
我要实现从student.txt读取信息并存入Student对象的vector,文件内容如下:
1 James 23 0 HaHa 7012 1 Jay-Z music
重载的>>运算符
std::istream& operator>> (std::istream& input, Student& student) { char id; std::string user, pswd; input >> id >> user >> pswd; if (id == '0') { student.setUsername(user); student.setPassword(pswd); } return input; }
填充vector的getStudents函数
void getStudents(std::fstream& file, std::vector< Student >& list) { char userType; std::string user, pswd; file.seekg(0, file.beg); Student newStudent; while (!file.eof()) { file >> newStudent; list.push_back(newStudent); } }
重载的<<输出运算符
std::ostream& operator<< (std::ostream& output, Student& student) { output << "Username: " << student.getUsername() << std::endl << "Password: "; output << student.getPassword() << std::endl; return output; }
main测试代码
vector<Student> students; fstream studentFile("Student.txt", ios::in); cout << "Students:\n\n"; getStudents(studentFile, students); for (int i = 0; i < (int)students.size(); i++) { cout << students[i]; }
异常输出结果
运行程序后得到以下异常输出:
Students: Username: Password: Username: HaHa Password: 7012 Username: HaHa Password: 7012 Teachers:
问题分析与修复方案
1. 循环条件错误:!file.eof()的误用
!file.eof()作为循环条件会导致读取失败后仍执行push_back。因为eof()仅在读取操作尝试越过文件末尾时才会置位,最后一次读取失败后,循环仍会执行一次,把无效的Student对象加入vector。
修复:将读取操作直接作为循环条件,读取成功才执行后续逻辑:
void getStudents(std::fstream& file, std::vector<Student>& list) { file.seekg(0, file.beg); Student newStudent; // 读取成功才进入循环 while (file >> newStudent) { list.push_back(newStudent); } }
2. id为'1'时Student对象未重置
当读取到id为'1'的行时,代码未修改Student对象的属性,导致它保留上一次的有效值(或默认空值):
- 第一次读取id='1'时,newStudent是默认构造的空对象,输出空的用户名/密码
- 第三次读取id='1'时,newStudent仍保留上一次的
HaHa/7012,导致重复加入
修复:在>>运算符中先重置Student对象状态:
std::istream& operator>> (std::istream& input, Student& student) { char id; std::string user, pswd; // 先重置对象属性 student.setUsername(""); student.setPassword(""); // 检查读取是否成功,失败直接返回 if (!(input >> id >> user >> pswd)) { return input; } if (id == '0') { student.setUsername(user); student.setPassword(pswd); } return input; }
3. 可选优化:过滤无效对象
如果只需要保留id='0'的有效Student,可以在加入vector前做判断:
while (file >> newStudent) { // 仅加入有有效用户名的对象 if (!newStudent.getUsername().empty()) { list.push_back(newStudent); } }
4. 输出运算符的const修正
输出操作不会修改Student对象,建议将参数改为const引用,并确保getter函数也是const成员:
// 输出运算符的参数改为const引用 std::ostream& operator<< (std::ostream& output, const Student& student) { output << "Username: " << student.getUsername() << "\nPassword: " << student.getPassword() << "\n"; return output; } // Student类中的getter需声明为const class Student { public: std::string getUsername() const { return username; } std::string getPassword() const { return password; } // ...其他成员 };
内容的提问来源于stack exchange,提问作者corl
相关产品推荐
相关产品推荐

