web-dev-qa-db-ja.com

std :: invalid_argumentエラーをスローする方法は?

C++のFractionクラスにオーバーロードされた演算子があります。これは、整数よりも整数の形式で標準入力から入力を受け取るように設計されています。つまり、1/2または32/4そしてそれらの値に基づいてFractionオブジェクトを初期化します。動作しますが、エラーを検出できません。

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

私はこのようなメソッドを呼び出します:

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

ただし、エラーがスローされると(garbageのようなものを入力します)、これにより、入力を求めずにループが永久に続行されます。これの理由は何ですか?

6
michaelsnowden

プログラムにどのような入力をするかを教えてくれないので、私は推測することしかできません。

Cinが解析できないものをシーケンスinputNumerator >> slash >> inputDenominatorとして入力すると、失敗状態または不良状態になります。例外は関数のelseブランチでスローされます(メイン関数のcatchブロックに例外のメッセージを出力することでテストできますし、テストする必要があります)。

Mainのループは続行されますが、cinは不良状態のままであるため、後続のすべての入力は再び失敗し、同じ例外が何度もスローされます。これを防ぐには、エラー処理中にcinの状態をクリアする必要があります。さらに、解析できない入力ストリームに不良文字がある場合は、それらを破棄するか、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.");
}
8
Arne Mertz