Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to throw std::invalid_argument error?

I have an overloaded operator in my Fraction class in C++ which is designed to take input from standard input in the form of an integer over an integer i.e. 1/2 or 32/4 and initialize a Fraction object based off of those values. It works, but I'm having trouble catching errors.

// gets input from standard input in the form of (hopefully) int/int
std::istream& operator >>(std::istream& inputStream, Fraction& frac)
{
    int inputNumerator, inputDenominator;
    char slash;

    if ((std::cin >> inputNumerator >> slash >> inputDenominator) && slash == '/')
    {
        if (inputDenominator == 0)
        {
            std::cout << "Denominator must not be 0." << std::endl;
            throw std::invalid_argument("Denominator must not be 0.");
        }
        frac.numerator = inputNumerator;
        frac.denominator = inputDenominator;

        frac.reduce();
    }
    else
    {
        throw std::invalid_argument("Invalid syntax.");
    }



    return inputStream;
}

I invoke the method like this:

 Fraction frac(1, 2);


while (true)
{
    try {
        std::cout << "Enter a fraction in the form int/int: ";
        std::cin >> frac;
        std::cout << frac;
    } catch (std::invalid_argument iaex) {
        std::cout << "Caught an error!" << std::endl;
    }
}

But whenever an error is thrown, (I'll enter something like garbage) this causes the loop to go on forever without asking for input. What is the reason for this?

like image 801
michaelsnowden Avatar asked Feb 11 '14 07:02

michaelsnowden


1 Answers

Since you don't tell us what input you give to your program, I can only guess:

You type something that cin can't parse as the sequence inputNumerator >> slash >> inputDenominator, so it goes into a fail state or bad state. The exception gets thrown in the else branch of your function (you can and should test that by printing the exception's message in your main function's catch block).

Your loop in main goes on, but cin is left in the bad state, so every following input fails again and the same exception is thrown again and again. To prevent that you should clear the state of cin during the error handling. In addition, if there are bad characters in the input stream that can't be parsed, they have to be thrown out, or ignored:

if ((std::cin >> inputNumerator >> slash >> inputDenominator) && slash == '/')
{
  /* ... */
}
else
{
    std::cin.clear(); // reset the fail flags
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //ignore the bad input until line end
    throw std::invalid_argument("Invalid syntax.");
}
like image 187
Arne Mertz Avatar answered Oct 15 '22 21:10

Arne Mertz