You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

重载>>运算符读取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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 00:25:30