使用stringstream读取文本行赋值Student时stoi异常的解决方法
文本行解析与哈希表插入异常修复
问题背景
需要读取文本文件中以单个空格分隔的行,每行包含id(整数)、firstname、lastname、department、gpa字段,示例行:
9528951 Adney Smith CS 4.2 //id fname lname dept gpa
现有代码运行时抛出异常:
terminate called after throwing an instance of 'std::invalid_argument' what(): stoi
调试发现Student变量无值,推测是stringstream使用不当导致解析失败,且id转int时因空值触发异常。
错误原因
- stringstream未正确绑定每行数据:代码中
stringstream ss(line)初始化时绑定的是空字符串,后续循环读取新的line后,未将ss重新绑定到当前line,导致始终读取空数据,所有字段变量为空。 - 未处理行内注释:示例行包含
//开头的注释,直接解析会把注释内容混入字段,导致解析异常。 - 空id触发stoi异常:空字符串调用
stoi()会直接抛出invalid_argument异常。
修复后的代码
#include <iostream> #include <fstream> #include <sstream> #include <string> #include <algorithm> // 假设Student和HashTable的定义已正确实现 template <typename T> class Student { private: std::string firstName; std::string lastName; std::string gpa; std::string department; public: void setFirstName(const std::string& fn) { firstName = fn; } void setLastName(const std::string& ln) { lastName = ln; } void setGPA(const std::string& g) { gpa = g; } void setDepartment(const std::string& d) { department = d; } }; template <typename T> class HashTable { public: void insert(int id, const Student<T>& student) { // 假设这里实现了正确的插入逻辑,包含stoi转换id的操作 } void displayHash() { // 假设这里实现了显示逻辑 } }; int main() { std::string line; std::ifstream myfile("enroll_test.txt"); HashTable<std::string> ht; std::string id_str, fname, lname, dept, gpa; if (!myfile.is_open()) { std::cout << "File failed to open" << std::endl; return 0; } while (std::getline(myfile, line)) { // 去除行内的注释部分 size_t comment_pos = line.find("//"); if (comment_pos != std::string::npos) { line = line.substr(0, comment_pos); } // 重置stringstream,绑定当前行 std::stringstream ss(line); // 解析字段 if (ss >> id_str >> fname >> lname >> dept >> gpa) { Student<std::string> student; student.setFirstName(fname); student.setLastName(lname); student.setGPA(gpa); student.setDepartment(dept); // 安全转换id为int try { int id = std::stoi(id_str); ht.insert(id, student); } catch (const std::invalid_argument& e) { std::cerr << "Invalid id format: " << id_str << std::endl; continue; } catch (const std::out_of_range& e) { std::cerr << "Id out of range: " << id_str << std::endl; continue; } } else { std::cerr << "Invalid line format: " << line << std::endl; continue; } } myfile.close(); ht.displayHash(); return 0; }
关键修复点
- 每次循环重新初始化stringstream:在循环内创建
std::stringstream ss(line),确保每次绑定当前读取的有效行数据。 - 处理行内注释:通过
line.find("//")定位注释起始位置,截取注释前的有效内容。 - 安全转换id:用
try-catch包裹stoi()调用,捕获无效格式或超出范围的异常,避免程序崩溃。 - 增加解析校验:判断
ss >> ...的返回值,确保字段解析成功后再创建Student对象,避免无效数据插入哈希表。
内容的提问来源于stack exchange,提问作者stackunderflow3
相关产品推荐
相关产品推荐

