重载 >> C++ 中 Date 类的运算符会导致无限循环

Overloading >> operator for Date class in c++ causes infinite loop

本文关键字:gt 无限循环 运算符 Date C++ 重载      更新时间:2023-10-16

我正在尝试重载 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");
}

正如我在评论中所说:

"clear() 函数应该清除流"是什么意思?它不会丢弃流内容,因此如果流中有垃圾(例如无法解析为 int 的字符"a"),它永远不会"清除"该垃圾,只会继续重试。我认为问题在于,清晰并没有做你认为它所做的事情。

如果流提取运算符无法提取

整数或分隔符错误,则不要从流提取运算符中抛出异常,而只抛出 failbit(也尝试使用更多空格来帮助使代码更具可读性):

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

您的代码有许多错误。do ... try ... catch循环可能是无限循环,也可能是不正确的。

如果在输入流上启用了异常,并且流提取语句中的解析在重载operator>>中失败,则会出现无限循环。您的代码永远不会重置流,因此一旦收到解析错误,您的代码就会陷入循环。永远。

如果未启用异常,并且输入被严重破坏到足以使流提取语句以某种方式将流标记为"坏",该怎么办?未启用异常,因此不会引发异常。您的代码(如果紧跟在流提取调用之后的 if 语句,则为 then 分支)将执行。这也不会引发异常。do ... try ... catch将成功。在这里,您的代码错误地接受错误的输入为有效。

我会重新设计您的示例,因为它依赖于能够输入多个项目,即 int char int char int。我会输入一个字符串。然后使用字符串流解析日期并检查其格式。

所以它可能是这样的:

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

我不确定这是否会修复任何无限循环,但这可能是检查输入的更好方法。