1. ホーム
  2. c++

[解決済み] std::invalid_argument エラーはどのように発生しますか?

2022-03-04 02:10:17

質問

の中にオーバーロードされた演算子があります。 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 ) このため、入力を求めることなく、ループが永遠に続いてしまいます。この原因は何でしょうか?

解決方法は?

プログラムにどのような入力を行っているか教えてくれないので、推測するしかありません。

あなたは、cinがシーケンスとして解析できないものを入力します。 inputNumerator >> slash >> inputDenominator そのため、フェールステートまたはバッドステートになります。例外は関数の else ブランチでスローされます (メイン関数の catch ブロックで例外のメッセージを表示することでテストできますし、そうする必要があります)。

main のループは続きますが cin が悪い状態のままなので、その後の入力がすべて失敗し、同じ例外が何度も投げられることになります。これを防ぐには、エラー処理中にcinの状態をクリアする必要があります。さらに、入力ストリームにパースできない悪い文字がある場合、それらを捨てなければならない、あるいは ignore d:

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