What is the difference between throw and throw with arg of caught exception?

前端 未结 2 2015
清酒与你
清酒与你 2020-12-09 09:59

Imagine two similar pieces of code:

try {
  [...]
} catch (myErr &err) {
  err.append(\"More info added to error...\");
  throw err;
}

相关标签:
2条回答
  • 2020-12-09 10:05

    In the second case according to C++ Standard 15.1/6 copy constructor is not used:

    A throw-expression with no operand rethrows the exception being handled. The exception is reactivated with the existing temporary; no new temporary exception object is created. The exception is no longer considered to be caught; therefore, the value of uncaught_exception() will again be true.

    In the first case new exception will be thrown according to 15.1/3:

    A throw-expression initializes a temporary object, called the exception object, the type of which is determined by removing any top-level cv-qualifiers from the static type of the operand of throw and adjusting the type from “array of T” or “function returning T” to “pointer to T” or “pointer to function returning T”, respectively. <...> The temporary is used to initialize the variable named in the matching handler (15.3). The type of the throw-expression shall not be an incomplete type, or a pointer or reference to an incomplete type, other than void*, const void*, volatile void*, or const volatile void*. Except for these restrictions and the restrictions on type matching mentioned in 15.3, the operand of throw is treated exactly as a function argument in a call (5.2.2) or the operand of a return statement.

    In both cases copy constructor is required at throw stage (15.1/5):

    When the thrown object is a class object, and the copy constructor used to initialize the temporary copy is not accessible, the program is ill-formed (even when the temporary object could otherwise be eliminated). Similarly, if the destructor for that object is not accessible, the program is ill-formed (even when the temporary object could otherwise be eliminated).

    0 讨论(0)
  • 2020-12-09 10:06

    Depending on how you have arranged your exception hierarchy, re-throwing an exception by naming the exception variable in the throw statement may slice the original exception object.

    A no-argument throw expression will throw the current exception object preserving its dynamic type, whereas a throw expression with an argument will throw a new exception based on the static type of the argument to throw.

    E.g.

    int main()
    {
        try
        {
            try
            {
                throw Derived();
            }
            catch (Base& b)
            {
                std::cout << "Caught a reference to base\n";
                b.print(std::cout);
                throw b;
            }
        }
        catch (Base& b)
        {
            std::cout << "Caught a reference to base\n";
            b.print(std::cout);
        }
    
        return 0;
    }
    

    As written above, the program will output:

    Caught a reference to base
    Derived
    Caught a reference to base
    Base

    If the throw b is replace with a throw, then the outer catch will also catch the originally thrown Derived exception. This still holds if the inner class catches the Base exception by value instead of by reference - although naturally this would mean that the original exception object cannot be modified, so any changes to b would not be reflected in the Derived exception caught by the outer block.

    0 讨论(0)
提交回复
热议问题