Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can be the number of uncaught exceptions be more than one?

The introduction of int uncaught_exceptions() noexcept; in C++17 instead of bool uncaught_exception() noexcept; begs the question whether it is possible to have more than one exception at the same time.

According to the en.cppreference.com:

Return value

  1. The number of uncaught exception objects in the current thread.

I tried to imagine such a case when it would be more than one.

Having racked my brains, I came up with only one idea: throw something in a destructor of local variable, within the same try block.

Yet it wouldn't do.

First, it violates the rule imposed on destructors forcing them to be noexcept. Second, it can be rectified by dint of noexcept(false), yet it would just call terminate instead of winding up at the catch block.

So it does not do the trick.

Finally, throwing anything within the catch block itself would be of the common run, nothing unusual. Since once one enters the catch block, uncaught_exceptions() decrements and becomes zero.

So I question if it is possible to conjure up such a case where uncaught_exceptions() would return more than 1?

like image 445
dronte7 Avatar asked Sep 12 '25 13:09

dronte7


1 Answers

The hint is given on the site you link:

Sometimes it's safe to throw an exception even while std::uncaught_exception() == true. For example, if stack unwinding causes an object to be destructed, the destructor for that object could run code that throws an exception as long as the exception is caught by some catch block before escaping the destructor.

Using this as recipe: We throw an exception, in a destructor of an object that is destroyed during stack unwinding we throw another one that is immediately catched, but while it is in the air we look at the number of uncaught exceptions (can be done via another object's destructor, tracker):

#include <iostream>
#include <exception>

struct tracker {
    ~tracker() {
        std::cout << std::uncaught_exceptions() << "\n";
    }
};

struct foo {
    ~foo() {
        try {
            tracker t;
            throw 123;
        } catch(...) {
            std::cout << std::uncaught_exceptions() << "\n";
        }
    }
};


int main() {
    try {
        foo f;
        throw 42;
    } catch(...) {}

}

Output:

2
1

The crucial point is that the second exception does not escape foos destructor. And to see both we need to call uncaught_exceptions before the catch block in foos destructor is entered. Thats why I used tracker. Once the catch block is entered it returns again 1.

I wouldn't know how to observe uncaught_exception == 2 without this double layer of stack-unwinding. Perhaps thats also a reason this was overlooked at first and only fixed in c++17. On the other hand, more layers could be added to have also uncaught_exception > 2.

like image 87
463035818_is_not_a_number Avatar answered Sep 15 '25 04:09

463035818_is_not_a_number