throw关键字的用法

时间:2012-08-09 11:54:15

标签: c++ try-catch throw

我最近开始用C ++编码,我对以下代码有疑问。我在使用'throw'关键字时遇到问题。在中位数或等级函数何时会出错? throw和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;

}

6 个答案:

答案 0 :(得分:4)

您可以从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.

} 

答案 1 :(得分:1)

函数double median(vector<double> vec)将抛出domain_error,以防{i}}传递包含任何元素。vec将因同样的原因抛出它 - 如果{{1}向量是空的。

执行double grade(double midterm, double final, const vector<double>& hw)后,hwthrow domain_error("...")将停止执行,控件将立即传递到最近的相应catch块,median位于{ {1}}。可以使用grade对象的函数catch (domain_error)来检索消息。

main

答案 2 :(得分:1)

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

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

如果G抛出X类型的异常,D是捕获类型X或其父类之一的异常的最近函数,或{ {1}},然后关闭函数...GFE将捕获异常。

在您的情况下,D

将捕获这两个例外
main

然而,在这个接球手的身体里,你没有太多用处:

} catch (domain_error) {

首先,您不打印cout << endl << "You must enter your grades. " "Please try again." << endl; return 1; 引发的实际消息。请参阅Bo Persson的答案。

其次,如果你想再试一次,你应该将整个主要内容放在一个循环中,而不是domain_error,而是return

最后,不要将异常视为一种闪亮的错误处理方式,they are not so great

答案 3 :(得分: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子句中的错误应该与抛出相同,否则,它将无法捕获它。

答案 4 :(得分:0)

您的问题已经得到解答,但我想提一下您写的内容。

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

你重载了函数grade并使你的代码混淆了。

您的median函数会在std::vector之前使用value参数,而不需要复制(在您的示例中)。

您正在检查两个向量的长度,内容完全相同两次,并抛出两个异常。 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;
}

答案 5 :(得分:0)

@Aesthete。我认为中位数函数会通过获取 std :: vector 参数。 在Accelerated C++书中,作者解释了原因。

  

中位数函数通过调用排序来更改其参数的值。复制参数可防止排序所做的更改从推送回到呼叫者。这种行为是有道理的,因为采用向量中位数不应该改变vecotr本身。

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

  

错误:'std :: vector&amp;'类型引用的初始化无效来自'const std :: vector'|

类型的表达式      

错误:传递'double median(std :: vector&amp;)'|

的参数1