3

我最近开始用 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;

}
4

6 回答 6

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.

} 
于 2012-08-09T11:59:29.800 回答
1

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

一旦throw domain_error("...")被执行,mediangrade将停止执行,控制将立即传递给最近的相应catch块,它catch (domain_error)位于main. 可以使用对象的函数检索what消息domain_error

} catch (const domain_error& ex) {
        cout << ex.what() << endl;
        return 1;
}
于 2012-08-09T12:03:00.407 回答
1

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

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

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

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

} catch (domain_error) {

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

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

首先,您没有打印使用domain_error. 请参阅Bo Persson的回答。

其次,如果你想再试一次,你应该把整个 main 放在一个循环中,而不是returncontinue.

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

于 2012-08-09T12:04:04.753 回答
1

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

那是什么意思?这意味着如果您调用该函数grade并引发错误,则有两种选择:

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

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

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

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

希望这一切都清楚了。

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

于 2012-08-09T12:07:02.610 回答
0

您的问题已经得到解答,但是关于您所写的内容,我想提几点。

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

您重载了该函数grade,并使您的代码在这样做时感到困惑。

您的median函数采用std::vector参数 by 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;
}
于 2012-08-09T12:24:35.677 回答
0

@Aesthete。我认为中函数应该按值采用std::vector参数。在Accelerated C++一书中,作者解释了原因。

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

如果不喜欢这个,我会在编译这个文件时得到以下错误信息(mingw32-g++.exe)

错误:从“const std::vector”类型的表达式中对“std::vector&”类型的引用进行无效初始化|

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

于 2014-05-08T10:33:09.790 回答