0

C ++でDateクラスの>>演算子をオーバーロードしようとしていますが、実行が最初のifステートメントに入ると、無限ループになります。助けていただけますか?

//operator
    istream& operator >>(istream& is,CustomDate& d){
        int day,month,year; 
        char ch1,ch2;
        string test;
        is>>skipws>>day>>ch1>>month>>ch2>>year;
        if(!is){
            is.clear(ios_base::failbit);
            return is;
        }
        if(ch1!='/' || ch2!='/')
            error("invalid date input");
        d = CustomDate(day,month,year);
        return is;
    }

これはそれを呼び出す関数です

CustomDate Menu::inputDate(){
    CustomDate date;
    cout<<"Input your departure date"<<endl;
    cin>>date;
    if(!cin){
        error("invalid date format");
    }
    return date;
}

そしてこれは関数を呼び出すループです

do{
    try{
        date = inputDate();
        validDate = true;
    }
    catch(runtime_error& e){
        cout<<"Date format not valid! must input as dd/mm/yyyy!"<<endl;
        validDate = false;
    }
}while(!validDate);

//customdate constructor
CustomDate::CustomDate()
    :day(1),month(1),year(2012){}

CustomDate::CustomDate(int day, int month, int year)
    :day(day),month(month),year(year){

    if(day<0 || day>30)
        error("Error: Date constructor");
    if(month<0 || month>12)
        error("Error: Date constructor");
    if(year<0)
        error("Error: Date constructor");
}
4

3 に答える 3

1

私がコメントで言ったように:

「clear()関数はストリームをクリアする必要がある」とはどういう意味ですか?ストリームの内容は破棄されないため、ストリームにジャンク(intとして解析できない文字「a」など)がある場合、そのジャンクを「クリア」することはなく、再試行を続けるだけです。問題は、クリアがあなたが思っていることをしないということだと思います。

整数を抽出できない場合や区切り文字が間違っている場合は、ストリーム抽出演算子から例外をスローするのではなく、フェイルビットだけをスローします(コードを読みやすくするために、より多くの空白を使用してみてください)。

istream& operator >>(istream& is, CustomDate& d){
    int day, month, year;
    char ch1, ch2;
    if (is >> day >> ch1 >> month >> ch2 >> year)
    {
        if (ch1 == '/' && ch2 == '/')
            d = CustomDate(day, month, year);
        else
            is.setstate(ios::failbit);
    }
    return is;
}

次に、失敗した抽出を処理しますinputDate

CustomDate inputDate(){
    CustomDate date;
    cout << "Input your departure date" << endl;
    if (cin >> date)
      return date;

    // something went wrong
    if (cin.eof())
        error("No more data in stream");
    else // cin.fail() is true, probably invalid date format
    {
        // clear error and discard input up to next newline
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
        error("invalid date format");
    }
}
于 2012-05-23T17:42:05.287 に答える
1

コードにいくつかのエラーがあります。do ... try ... catchループは潜在的に無限ループであり、また潜在的に正しくありません。

入力ストリームで例外を有効にしていて、オーバーロードされたでストリーム抽出ステートメントの解析が失敗した場合、無限ループが発生しますoperator>>。コードがストリームをリセットすることはないため、解析エラーが発生すると、コードはループに陥ります。永遠に。

例外が有効になっておらず、ストリーム抽出ステートメントが何らかの方法でストリームを「不良」としてマークするのに十分な入力がマングルされている場合はどうなりますか?例外は有効になっていないため、例外はスローされません。コード(ストリーム抽出呼び出しの直後のifステートメントの場合はthenブランチ)が実行されます。これも例外をスローしません。do ... try ... catch成功します。ここで、コードは誤って不正な入力を有効として受け入れます。

于 2012-05-23T18:31:18.397 に答える
0

複数の項目、つまりint char int char intを入力できることに依存しているため、例を作り直します。1つの文字列を入力します。次に、文字列ストリームを使用して日付を解析し、その形式を確認します。

したがって、次のようになります。

istream& operator >>(istream& is,CustomDate& d){
    string dateStr;
    is>>dateStr;
    istringstream iss(dateStr);
    int day,month,year; 
    char ch1,ch2;
    if(!(iss>>day>>ch1>>month>>ch2>>year)){
        error("invalid date input");
        return is;
    }
    if(ch1!='/' || ch2!='/'){
        error("invalid date format use m/d/y");
        return is;
    }
    d = CustomDate(day,month,year);
    return is;
}

これで無限ループが修正されるかどうかはわかりませんが、入力を確認するためのより良い方法かもしれません。

于 2012-05-23T16:55:43.113 に答える