实验6
实验任务1:
源代码contestant.hpp
1 #pragma once 2 #include<iomanip> 3 #include<iostream> 4 #include<string> 5 6 struct Contestant{ 7 long id; 8 std::string name; 9 std::string major; 10 int solved; 11 int penalty; 12 }; 13 14 inline std::ostream& operator<<(std::ostream& out,const Contestant& c){ 15 out << std::left; 16 out << std::setw(15) << c.id 17 << std::setw(15) << c.name 18 << std::setw(15) << c.major 19 << std::setw(15) << c.solved 20 << std::setw(15) << c.penalty; 21 22 return out; 23 } 24 25 inline std::istream& operator>>(std::istream& in,Contestant& c){ 26 in >> c.id >> c.name >> c.major >> c.solved >> c.penalty; 27 return in; 28 }
源代码utils.hpp
1 #pragma once 2 #include<fstream> 3 #include<iostream> 4 #include<stdexcept> 5 #include<string> 6 #include<vector> 7 #include "contestant.hpp" 8 9 inline bool cmp_by_solve(const Contestant& a,const Contestant& b){ 10 if(a.solved!=b.solved) 11 return a.solved>b.solved; 12 return a.penalty<b.penalty; 13 } 14 15 inline void write(std::ostream& os,const std::vector<Contestant>& v){ 16 for(const auto& x:v) 17 os << x << '\n'; 18 } 19 20 inline void print(const std::vector<Contestant>& v){ 21 write(std::cout,v); 22 } 23 24 inline void save(const std::string& filename,const std::vector<Contestant>& v){ 25 std::ofstream os(filename); 26 if(!os) 27 throw std::runtime_error("fail to open " + filename); 28 write(os,v); 29 } 30 31 inline std::vector<Contestant> load(const std::string& filename){ 32 std::ifstream is(filename); 33 if(!is) 34 throw std::runtime_error("fail to open " + filename); 35 std::string line; 36 std::getline(is,line); 37 38 std::vector<Contestant> v; 39 Contestant t; 40 int seq; 41 while(is >> seq >> t) 42 v.push_back(t); 43 44 return v; 45 }
源代码task1.cpp
1 #include<algorithm> 2 #include<iostream> 3 #include<stdexcept> 4 #include<vector> 5 #include "contestant.hpp" 6 #include "utils.hpp" 7 8 const std::string in_file="./data.txt"; 9 const std::string out_file="./ans.txt"; 10 11 void app(){ 12 std::vector<Contestant> contestants; 13 try{ 14 contestants=load(in_file); 15 std::sort(contestants.begin(),contestants.end(),cmp_by_solve); 16 print(contestants); 17 save(out_file,contestants); 18 }catch(const std::exception& e){ 19 std::cerr << e.what() << '\n'; 20 return; 21 } 22 } 23 24 int main(){ 25 app(); 26 }
运行结果截图:

ans.txt:

问题1:
(1)std::ostream是所有输出流的基类,std::cout和std::ofstream都继承自std::ostream。基类引用可以接受所有派生类对象。
(2)不需要,write()函数接收std::ostream&参数,可以接受任何继承自std::ostream类的对象。
问题2:
if(!os)
throw std::runtime_error("fail to open " + filename);
if(!is)
throw std::runtime_error("fail to open " + filename);
(1)save()函数:当无法打开指定文件进行写入时会抛出异常;load()函数:当无法打开指定文件进行读取时会抛出异常。
(2)异常被app()中catch(conat std::exception& e)捕获,会将异常信息输出,然后返回,程序终止。
问题3:可以,功能、性能、结果一致。
问题4:
(1)
文件中第7行数据,缺失的解题数和罚时字段输出了随机值,第7行之后的数据没有被读取。出现这种问题的原因是load()函数使用is>>seq>>t读取,当字段缺失时operator>>读取失败,流进入错误状态,循环提前终止。
(2)
1 inline std::vector<Contestant> load(const std::string& filename){ 2 std::ifstream is(filename); 3 if(!is) 4 throw std::runtime_error("fail to open " + filename); 5 std::string line; 6 std::getline(is,line); 7 8 std::vector<Contestant> v; 9 int num=1; 10 Contestant t; 11 while(std::getline(is,line)){ 12 if(line.empty()){ 13 std::cerr << "警告:第" << num << "行为空行,已跳过" << std::endl; 14 continue; 15 } 16 std::istringstream iss(line); 17 if(!(iss >> num >> t.id >> t.name >> t.major >> t.solved >> t.penalty)){ 18 std::cerr << "错误:第" << num << "行数据格式不正确,已跳过" << std::endl; 19 continue; 20 } 21 v.push_back(t); 22 num++; 23 } 24 25 return v; 26 }

实验任务2:
源代码student.hpp
1 #pragma once 2 #include<iostream> 3 #include<string> 4 5 class Student{ 6 public: 7 Student()=default; 8 ~Student()=default; 9 const std::string get_major() const; 10 int get_grade() const; 11 friend std::ostream& operator<<(std::ostream& os,const Student& s); 12 friend std::istream& operator>>(std::istream& is,Student& s); 13 14 private: 15 int id; 16 std::string name; 17 std::string major; 18 int grade; 19 };
源代码student.cpp
1 #include<iostream> 2 #include<string> 3 #include<iomanip> 4 #include "student.hpp" 5 6 const std::string Student::get_major() const{ 7 return major; 8 } 9 10 int Student::get_grade() const{ 11 return grade; 12 } 13 14 std::ostream& operator<<(std::ostream& os,const Student& s){ 15 os << std::left; 16 os << std::setw(15) << s.id 17 << std::setw(15) << s.name 18 << std::setw(15) << s.major 19 << std::setw(15) << s.grade; 20 return os; 21 } 22 23 std::istream& operator>>(std::istream& is,Student& s){ 24 is >> s.id >> s.name >> s.major >> s.grade; 25 return is; 26 }
源代码stumgr.hpp
1 #pragma once 2 #include<string> 3 #include<vector> 4 #include "student.hpp" 5 6 class StuMgr{ 7 public: 8 void load(const std::string& file); 9 void sort(); 10 void print() const; 11 void save(const std::string& file) const; 12 13 private: 14 void write(std::ostream &os) const; 15 16 private: 17 std::vector<Student> students; 18 };
源代码stumgr.cpp
1 #include<iostream> 2 #include<fstream> 3 #include<algorithm> 4 #include<stdexcept> 5 #include<string> 6 #include<vector> 7 #include "stumgr.hpp" 8 9 bool func(const Student& a,const Student& b){ 10 if(a.get_major()!=b.get_major()) 11 return a.get_major()<b.get_major(); 12 return a.get_grade()>b.get_grade(); 13 } 14 15 void StuMgr::load(const std::string& file){ 16 std::ifstream is(file); 17 if(!is) 18 throw std::runtime_error("fail to open " + file); 19 std::string line; 20 std::getline(is,line); 21 22 Student t; 23 while(is >> t){ 24 students.push_back(t); 25 } 26 } 27 28 void StuMgr::sort(){ 29 std::sort(students.begin(),students.end(),func); 30 } 31 32 void StuMgr::print() const{ 33 if(students.empty()){ 34 std::cout << "没有学生数据\n"; 35 return; 36 } 37 write(std::cout); 38 } 39 40 void StuMgr::save(const std::string& file) const{ 41 std::ofstream os(file); 42 if(!os) 43 throw std::runtime_error("fail to open " + file); 44 write(os); 45 } 46 47 void StuMgr::write(std::ostream &os) const{ 48 for(const auto& s:students) 49 os << s << '\n'; 50 }
源代码task2.cpp
1 #include<iostream> 2 #include<limits> 3 #include<string> 4 #include "stumgr.hpp" 5 6 const std::string in_file="./data.txt"; 7 const std::string out_file="./ans.txt"; 8 9 void menu(){ 10 std::cout << "\n**********简易应用**********\n" 11 << "1.加载文件\n" 12 << "2.排序\n" 13 << "3.打印到屏幕\n" 14 << "4.保存到文件\n" 15 << "5.退出\n" 16 << "请选择:"; 17 } 18 19 void app(){ 20 StuMgr mgr; 21 while(true){ 22 menu(); 23 int choice; 24 std::cin >> choice; 25 26 try{ 27 switch(choice){ 28 case 1:mgr.load(in_file); 29 std::cout << "加载成功\n";break; 30 case 2:mgr.sort(); 31 std::cout << "排序已完成\n";break; 32 case 3:mgr.print(); 33 std::cout << "打印已完成\n";break; 34 case 4:mgr.save(out_file); 35 std::cout << "导出成功\n";break; 36 case 5:return; 37 default:std::cout << "不合法输入\n"; 38 } 39 } 40 catch(const std::exception& e){ 41 std::cout << "Error:" << e.what() << '\n'; 42 } 43 } 44 } 45 46 int main(){ 47 app(); 48 }
运行结果截图:


ans.txt:

拓展:
1 void StuMgr::load(const std::string& file){ 2 std::ifstream is(file); 3 if(!is) 4 throw std::runtime_error("fail to open " + file); 5 std::string line; 6 int num=1; 7 std::getline(is,line); 8 9 while(std::getline(is,line)){ 10 num++; 11 if(line.empty()){ 12 std::cerr << "[Warning] line " << num << " " << "empty" << " , skipped: " << line << std::endl; 13 continue; 14 } 15 Student t; 16 std::istringstream iss(line); 17 if(!(iss >> t)){ 18 std::cerr << "[Warning] line " << num << " " << "format error" << " , skipped: " << line << std::endl; 19 continue; 20 } 21 if(t.get_grade()<0||t.get_grade()>100){ 22 std::cerr << "[Warning] line " << num << " " << "grade invalid" << " , skipped: " << line << std::endl; 23 continue; 24 } 25 students.push_back(t); 26 } 27 }



实验总结:
本次实验学习了解异常处理相关知识,针对脏数据(空白行、字段缺失、值非法)增加异常处理机制,提高程序的容错能力与健壮性。当处理严重错误时,使用throw抛出异常;当只需要显示警告,程序可以继续向后运行时,使用std::cerr抛出异常。

浙公网安备 33010602011771号