3

I've recently started coding in C++ and i'm having doubts about the following code. I'm having trouble with the 'throw' keyword. In the median or grade function when will it give an error? What is the exact usage of throw and domain_error? Will i ever get the error message from the grade or median function?

#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;

}
Shahbaz
  • 46,337
  • 19
  • 116
  • 182
pratZ
  • 3,078
  • 2
  • 20
  • 29

6 Answers6

4

You can get the message from the exception in the catchstatement.

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.

} 
Bo Persson
  • 90,663
  • 31
  • 146
  • 203
1

The function double median(vector<double> vec) will throw a domain_error in case vec being passed contains no elements.The double grade(double midterm, double final, const vector<double>& hw) will throw it for the same reason - if a hw vector is empty.

Once throw domain_error("...") is executed, median or grade will stop its execution and the control will be passed immediately to the closest corresponding catch block, which is catch (domain_error) in main. A message can be retrieved using a function whatof domain_error object.

} catch (const domain_error& ex) {
        cout << ex.what() << endl;
        return 1;
}
Maksim Skurydzin
  • 10,301
  • 8
  • 40
  • 53
1

Imagine a series of functions calling each other:

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

If G throws an exception of type X, and D is the closest function that catches an exception of type X, or one of its parents, or ..., then the functions G, F and E will be closed and D will catch the exception.

In your case, both exceptions will be caught by main:

} catch (domain_error) {

In the body of this catcher however, you don't do much useful:

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

First of all, you are not printing the actual message that was thrown with domain_error. See Bo Persson's answer for that.

Second, if you want to try again, you should put the whole main in a loop, and instead of return, you continue.

Finally, don't think of exceptions as a shiny great way of error handling, they are not so great.

Community
  • 1
  • 1
Shahbaz
  • 46,337
  • 19
  • 116
  • 182
1

The throw keywords means that if this line of code is reached (i.e the statement inside the if is true) then it would throw an error up the stack, until is it caught.

What is that means? It means that if you have a call for the function grade and the error is thrown, there are two options:

1) If the call to the function is inside a try and catch block, i.e:

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

then it will catch it, perform what's inside the catch clause, and the program will continue.

2) If the call is not inside a try and catch block, then it will pop the function that called this one, recursively, until a try and catch block is reached, or no more functions in the stack. in that case, it will most likely crush (that's what it does in java) due to uncaught exception.

Hope that's clear things up.

Also, note that the error inside the catch clause, should be the same as being thrown, otherwise, it won't catch it.

La bla bla
  • 8,558
  • 13
  • 60
  • 109
0

Your question has already been answered, but there are a few things I'd like to mention about what you've written.

In my personal opinion, I think your use of exception here is entirely unecessary.

You overloaded the function grade and made your code confusing in doing so.

Your median function takes a std::vector parameter by value, where there is no need for a copy to occur (in your example).

You're checking the length of the two vectors with the exact same contents twice, and throwing two exceptions. The exception in median will never get thrown in your example.

All this could be avoided.

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;
}

In your main:

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
  • 18,622
  • 6
  • 36
  • 45
0

@Aesthete .I think the median function shouble take a std::vector parameter by value . In the Accelerated C++ book,the author explained the reason.

The median function changes the value of its parameter by calling sort.Copying the argument prevents changes made by sort from propageting back to the caller. This behavior makes sense,because taking the median of a vector should not change the vecotr itself.

If don't like this, I will get the following error message when this file is compiled(mingw32-g++.exe)

error: invalid initialization of reference of type 'std::vector&' from expression of type 'const std::vector'|

error: in passing argument 1 of 'double median(std::vector&)'|

Community
  • 1
  • 1
Barloc
  • 1
  • 1