Does function try block allows us to resolve a exception?

218 views Asked by At

So I was reading about function try block in this link. And there was a line that describes the difference between normal try block and function try block like this

unlike normal catch blocks, which allow you to either resolve an exception, throw a new exception, or rethrow an existing exception, with function-level try blocks, you must throw or rethrow an exception

But then I try to write a function try block like this

#include <iostream> 

int add(int a, int b) try {
    throw 1;
    return a + b;
}
catch (int) {
    std::cout << "catch in add()";
}

int main()
{
    try {
        add(1, 2);
    }
    catch (int) {
        std::cout << "catch in main()";
    }
}

The output is

catch in add()

If function try block doesn't allow us to resolve an exception, then how come catch in main() doesn't got printed

3

There are 3 answers

0
eerorika On

Does function try block allows us to resolve a exception?

Yes.

The mandatory automatic throw only applies to a few cases such as constructors and destructors. The example function is neither a constructor nor a destructor.

P.S. The behaviour of the example is undefined because it fails to return a value from non-void function.

0
StoryTeller - Unslander Monica On

And there was a line that describes the difference between normal try block and function try block like this

And that line is inaccurate. Function try blocks for regular functions, behave pretty much as if they were simply the only contents of the function. Meaning, your definition of add acts exactly the same as

int add(int a, int b) {
    try {
        throw 1;
        return a + b;
    }
    catch (int) {
        std::cout << "catch in add()";
    }
}

The difference arises in constructors. For one, a function level try block is the only way to catch exceptions raised while initializing the members of the class.

And secondly, once an exception is thrown from a member's initialization, the constructor cannot complete, and so the object is not initialized. It is here that we are not allowed to simply swallow the exception. If initialization fails by throwing an exception, that exception must be propagated or translated to another type and rethrown.

The example on the page you linked summarizes that in code

B(int x) try : A(x) // note addition of try keyword here
{
}
catch (...) // note this is at same level of indentation as the function itself
{
            // Exceptions from member initializer list or constructor body are caught here
 
            std::cerr << "Exception caught\n";
 
            // If an exception isn't explicitly thrown here, the current exception will be implicitly rethrown
}
0
cdhowie On

The tutorial you're following is partly mistaken. It says this:

Finally, unlike normal catch blocks, which allow you to either resolve an exception, throw a new exception, or rethrow an existing exception, with function-level try blocks, you must throw or rethrow an exception. If you do not explicitly throw a new exception, or rethrow the current exception (using the throw keyword by itself), the exception will be implicitly rethrown up the stack.

This is completely incorrect with regards to functions.

However, this is true with regards to constructors and destructors. The C++17 standard says this:

13 If a return statement appears in a handler of the function-try-block of a constructor, the program is ill-formed.

14 The currently handled exception is rethrown if control reaches the end of a handler of the function-try-block of a constructor or destructor. Otherwise, flowing off the end of the compound-statement of a handler of a function-try-block is equivalent to flowing off the end of the compound-statement of that function.

-- N4713 [except.handle] (emphasis mine)

The first sentence of point 14 confirms this behavior for constructors and destructors. The second sentence directly contradicts the information in the tutorial you are following, because they did not distinguish the two cases.


Note that your code causes undefined behavior because the function's catch block does not throw an exception nor does it return a value, and the function doesn't return void. You must return a value from the catch block to avoid UB.