实验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 }

运行结果截图:

image

ans.txt:

image

 问题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)image

文件中第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 }

image

 

实验任务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 }

运行结果截图:

image

image

ans.txt:

image

拓展:

 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 }

image

image

image

 

 

实验总结:

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

posted @ 2025-12-19 20:58  知之为吃吃  阅读(0)  评论(0)    收藏  举报