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("...")が実行されると、またはmedianそのgrade実行が停止し、制御はすぐに最も近い対応する 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型 の例外をスローし、 が型XD例外をキャッチする最も近い関数X、またはその親の 1 つ、またはである場合、...関数およびは閉じられ、例外をキャッチします。GFED

あなたの場合、両方の例外がキャッチされmainます:

} catch (domain_error) {

ただし、このキャッチャーの本体では、あまり役に立ちません。

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

まず第一に、でスローされた実際のメッセージを出力していませんdomain_errorそれについては、 Bo Perssonの回答を参照してください。

次に、やり直したい場合は、メイン全体をループに入れて、 の代わりreturncontinue.

最後に、例外を非常に優れたエラー処理方法と考えないでください。例外はそれほど優れたものではありません

于 2012-08-09T12:04:04.753 に答える
1

キーワードは、このthrowコード行に到達した場合 (つまり、if 内のステートメントが true の場合)、キャッチされるまでスタックにエラーをスローすることを意味します。

どういう意味ですか?関数の呼び出しがgradeあり、エラーがスローされた場合、2 つのオプションがあることを意味します。

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パラメータを取ります(あなたの例では)。value

まったく同じ内容の 2 つのベクトルの長さを 2回チェックし、2 つの例外をスローしています。あなたの例では例外がスローさ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 .私は、中央値関数 shouble が値によってstd::vectorパラメータを取ると思います。Accelerated C++の本で、著者はその理由を説明しました。

median関数は、 sortを呼び出すことによってそのパラメーターの値を変更します。引数をコピーすると、 sortによって行われた変更が呼び出し元に反映されなくなります。ベクトルの中央値を取得しても、ベクトル自体は変更されないため、この動作は理にかなっています。

これが気に入らなければ、このファイルをコンパイルしたときに次のエラー メッセージが表示されます (mingw32-g++.exe)。

エラー: タイプ 'const std::vector' の式からのタイプ 'std::vector&' の参照の無効な初期化 |

エラー: 'double median(std::vector&)' の引数 1 を渡す際に |

于 2014-05-08T10:33:09.790 に答える