2

According to cppreference

The catch (...) handler matches exceptions of any type. [...] This handler may be used to ensure that no uncaught exceptions can possibly escape from a function that offers nothrow exception guarantee.

However, given the following program:

struct throwing_dtor_t {
  ~throwing_dtor_t() noexcept(false) { throw 123; }
};

int main() {
  try {
    try {
      throw throwing_dtor_t{};
    } catch (...) {
    }
  } catch (int i) {
    return i;
  }
  return 0;
}

Returns 123. Hence we can see that an exception has escaped the (...) handler.

Does this program has undefined behavior ? (I couldn't see anything in the standard saying so)

8
  • 2
    You throw from the (hidden) exception of ... Commented Jun 27 at 8:53
  • Clang doesn't catch that exception BTW Demo. Commented Jun 27 at 8:55
  • 1
    It says may be used, not "will automagically handle all cases". Like when throwing a new exception in the catch handler. Commented Jun 27 at 8:59
  • clang 20 return 0 but clang 18 and gcc 13 returns 123. (x86_64 linux) Commented Jun 27 at 9:02
  • @BoP Ok I finally understood what you meant. I now realize my question it is not a good question <_<. Commented Jun 27 at 9:15

2 Answers 2

8

The thrown exception does match the catcher. What happens is that another exception is thrown as the object is destructed from the catch block after being caught. You can more easily see the same by changing the code to this:

struct throwing_dtor_t {
  ~throwing_dtor_t() noexcept(false) { throw 123; }
};

int main(){
    try{
        try{
            throw throwing_dtor_t{};
        }
        catch(const throwing_dtor_t&){
            std::cout<<"caught throwing_dtor_t" << std::endl;
        }
    }
    catch(int i){
        std::cout<<i<<std::endl;
    }
}

So what your code is doing is something very similar to:

int main(){
    try{
        try{
            throw 1;
        }
        catch(...){
            throw 2;
        }
    }
    catch(int i){
        std::cout<<i<<std::endl;
    }
}

So of course the outer catch will get the rethrown exception

Sign up to request clarification or add additional context in comments.

6 Comments

I think it does match. From the standard: > A ... in a handler's exception-declaration specifies a match for any exception.
Constructor might throw (even if it is dangerous), it is not UB per se. I don't know though if exception can throw...
> The undefined behavior due to an exception leaving a destructor. Can you reference the standard regarding this undefined behavior?
@Dorian yeah that was it typo. I meant that it does match, but another exception is thrown during the destruction of throwing_dtor_t after that scope of catch(...) block is over
Right, I misunderstood that part. But the point still stands that catch(...) is still correctly matching the thrown exception and throwing it's own exception. We didn't escape the handler, but threw another exception.
|
3

... matches exceptions of any type.

try {
    throw throwing_dtor_t{};
} catch (...) {
    // catch throwing_dtor_t
}

Issue is to know when ~throwing_dtor_t() noexcept(false) { throw 123; } is called (to be able to catch that int).

According to https://cppreference.com/w/cpp/language/throw.html (since C++11) emphasis mine:

The points of potential destruction for the exception object are:

  • When an active handler for the exception exits by any means other than rethrowing, immediately after the destruction of the object (if any) declared in the “parameter list” in the handler.
  • When an object of type std::exception_ptr that refers to the exception object is destroyed, before the destructor of std::exception_ptr returns.
    Among all points of potential destruction for the exception object, there is an unspecified last one where the exception object is destroyed. All other points happen before that last one. The implementation may then deallocate the memory for the exception object in an unspecified way.

So it is mainly unspecified when the exception is destroyed.

it might be destroyed at exit of catch block, then, the surrounding catch (int i) will catch it, or it might be destroyed even after the catch (int) and so be uncaught...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.