Search code examples
c++dateoverloadinginfiniteistream

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


I'm trying to overload the >>operator for a Date class in c++ but the it goes in infinite loop when the run goes into the first if statement, can you please help me?

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

This is the function that calls it

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

And this is the the loop that calls the function

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

Solution

  • As I said in a comment:

    What do you mean by "the clear() function should clear the stream"? It doesn't discard the stream contents, so if there's junk in the stream (such as the character 'a' that can't be parsed as an int) it will never "clear" that junk and will just keep retrying. I think the problem is that clear doesn't do what you think it does.

    Rather than throwing an exception from the stream extraction operator just the failbit if it can't extract integers or the separator characters are wrong (also try using more whitespace to help make the code more readable):

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

    Then handling failed extractions in 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");
        }
    }