抛出关键字的用法

Usage of throw keyword

本文关键字:用法 关键字 出关      更新时间:2023-10-16

我最近开始用C++编码,我对以下代码有疑问。我在使用"投掷"关键字时遇到问题。在中位数或等级函数中,它什么时候会给出误差?投掷和domain_error的确切用途是什么?我是否会从成绩或中位数函数收到错误消息?

#include<iostream>
#include<string>
#include<vector>
#include<iomanip>
#include<ios>
#include<algorithm>
#include<stdexcept>
using std::cout; using std::cin;
using std::vector; using std::endl;
using std::string; using std::streamsize;
using std::setprecision; using std::domain_error;
using std::istream;
double grade(double midterm, double final, double homework)
{
   return 0.2*midterm+0.4*final+0.4*homework;
}
double median(vector<double> vec)
{
   typedef vector<double>::size_type vec_sz;
   vec_sz size= vec.size();
   if(size==0)
   {
       throw domain_error("Median of an empty vector"); //when will i get this error msg??
   }
   sort(vec.begin(),vec.end());
   vec_sz mid=size/2;
   return size%2==0?(vec[mid]+vec[mid-1])/2:vec[mid];
}
double grade(double midterm, double final, const vector<double>& hw)
{
   if(hw.size()==0)
   {
       throw domain_error("Student has done no homework");// when will i get this error?
   }
   return grade(midterm, final, median(hw));
}
istream& read_hw(istream& in, vector<double>& hw)
{
     if(in)
     {
         hw.clear();
         double x;
         while(in>>x)
         hw.push_back(x);
         in.clear();
     }
     return in;
}
int main()
{
    string name;
    cout<<"Please enter your name:";
    cin>>name;
    cout<<"Hello "<<name<<"!"<<endl;
    cout << "Please enter your midterm and final exam grades: ";
    double midterm, final;
    cin >> midterm >> final;
    cout << "Enter all your homework grades, "
                   "followed by end-of-file: ";
    vector<double> homework;
    read_hw(cin, homework);
    try {
        double final_grade = grade(midterm, final, homework);
        streamsize prec = cout.precision();
        cout << "Your final grade is " << setprecision(3)
        << final_grade << setprecision(prec) << endl;
    } catch (domain_error) {
        cout << endl << "You must enter your grades. "
        "Please try again." << endl;
        return 1;
    }
    return 0;
}

您可以从 catch 语句中的异常中获取消息。

try { 
    double final_grade = grade(midterm, final, homework); 
    streamsize prec = cout.precision(); 
    cout << "Your final grade is " << setprecision(3) << final_grade 
         << setprecision(prec) << endl; 
} catch (const domain_error& error) {
    cout << error.what();  // <-- Will print your message.
} 

想象一系列相互调用的函数:

A -> B -> C -> D -> E -> F -> G

如果 G 抛出类型 X 的异常,并且 D 是捕获类型 X 的异常的最接近的函数,或者它的父级之一,或...,则函数GFE 将被关闭,D将捕获异常。

在您的情况下,这两种异常都将被main捕获:

} catch (domain_error) {

然而,在这个捕手的身体中,你没有做太多有用的事情:

cout << endl << "You must enter your grades. "
    "Please try again." << endl;
return 1;

首先,您没有打印随 domain_error 抛出的实际消息。请看薄佩尔松的回答。

其次,如果你想再试一次,你应该把整个主线放在一个循环中,而不是return,你continue

最后,不要将异常视为错误处理的出色方法,它们并不是那么好。

函数

double median(vector<double> vec)将抛出一个domain_error,以防传递vec不包含任何元素。double grade(double midterm, double final, const vector<double>& hw)会出于同样的原因抛出它 - 如果一个hw向量为空。

一旦throw domain_error("...")被执行,mediangrade将停止其执行,并且控制权将立即传递到最近的相应 catch 块,该块在 maincatch (domain_error)。可以使用domain_error对象的函数what来检索消息。

} catch (const domain_error& ex) {
        cout << ex.what() << endl;
        return 1;
}

> throw 关键字意味着如果到达这一行代码(即 if 中的语句为 true),那么它将在堆栈中抛出错误,直到它被捕获。

这是什么意思?这意味着,如果您调用了函数grade并抛出错误,则有两个选项:

1) 如果对函数的调用位于try and catch块内,即:

try {
    grade();
} catch(domain_error) {
    cout << "An error occured" << endl;
}

然后它将捕获它,执行 catch 子句中的内容,程序将继续。

2)如果调用不在 try 和 catch 块内,那么它将递归地弹出调用此函数的函数,直到到达 try 和 catch 块,或者堆栈中没有其他函数。在这种情况下,由于未捕获的异常,它很可能会粉碎(这就是它在 Java 中所做的)。

希望事情清楚了。

另外,请注意,catch 子句中的错误应该与抛出的错误相同,否则,它不会捕获它。

你的问题已经回答了,但关于你写的东西,我想提几件事。

在我个人看来,我认为你在这里使用exception是完全没有必要的。

您使函数grade重载,并在此过程中使代码混乱。

您的median函数通过 value 获取std::vector参数,其中不需要进行复制(在您的示例中)。

您两次检查具有完全相同内容的两个向量的长度,并引发两个异常。median中的异常永远不会在您的示例中引发。

所有这些都是可以避免的。

double median(vector<double>& vec)
{       
   sort(vec.begin(),vec.end());
   vec_sz mid = size/2;
   return size%2==0?(vec[mid]+vec[mid-1])/2:vec[mid];
}
double grade(double midterm, double final, double homework)
{
  return 0.2*midterm+0.4*final+0.4*homework;
}

在您的主要:

if(hw.size())
{
  double final_grade = grade(midterm, final, median(hw));
}
else
{
  cout << endl << "You must enter your grades. "
  "Please try again." << endl;
  return 1;
}

@Aesthete .我认为中值函数 shouble 按获取 std::vector 参数。在加速C++书中,作者解释了原因。

median 函数通过调用 sort 来更改其参数的值。复制参数可防止通过排序所做的更改传回调用方。这种行为是有道理的,因为取向量的中位数不应该改变 vecotr 本身。

如果不喜欢这样,编译此文件时会收到以下错误消息(mingw32-g++.exe)

错误:从类型为"const std::vector"的表达式初始化类型"std::vector&"的引用无效|

错误:在传递"双中位数(std::vector&)"的参数 1 时|