Function-try-block

From cppreference.com
< cpp‎ | language

Establishes an exception handler around the body of a function.

[edit] Syntax

The function-try-block is one of the alternative syntax forms for function-body, which is a part of function definition.

try ctor-initializer(optional) compound-statement handler-sequence
ctor-initializer - member initializer list, only allowed in constructors
compound-statement - the brace-enclosed sequence of statements that constututes the body of a function
handler-sequence - sequence of one or more catch-clauses

[edit] Explanation

A function-try-block associates a sequence of catch clauses with the entire function body, and with the member initializer list (if used in a constructor) as well. Every exception thrown from any statement in the function body, or (for constructors) from any member or base constructor, or (for destructors) from any member or base destructor, transfers control to the handler-sequence the same way an exception thrown in a regular try block would.

struct S {
    std::string m;
    S(const std::string& arg) try : m(arg, 100) {
        std::cout << "constructed, mn = " << m << '\n';
    } catch(const std::exception& e) {
        std::cerr << "arg=" << arg << " failed: " << e.what() << '\n';
    } // implicit throw; here
};

Before any catch clauses of a function-try-block on a constructor are entered, all fully-constructed members and bases have already been destroyed.

If the function-try-block is on a delegating constructor, which called a non-delegating constructor that completed successfully, but then the body of the delegating constructor throws, the destructor of this object will be completed before any catch clauses of the function-try-block are entered. (since C++11)

Before any catch clauses of a function-try-block on a destructor are entered, all bases and non-variant members have already been destroyed.

The behavior is undefined if the catch-clause of a function-try-block used on a constructor or a destructor accesses a base or a non-static member of the object.

Every catch-clause in the function-try-block for a constructor must terminate by throwing an exception. If the control reaches the end of such handler, the current exception is automatically rethrown as if by throw;. The return statement is not allowed in any catch clause of a constructor's function-try-block.

Reaching the end of a catch clause for a function-try-block on a destructor also automatically rethrows the current exception as if by throw;, but a return statement is allowed.

For all other functions, reaching the end of a catch clause is equivalent to return; if the function's return type is (possibly cv-qualified) void, otherwise the behavior is undefined.

[edit] Notes

The primary purpose of function-try-blocks is to log or modify, and then rethrow the exceptions thrown from the member initializer list in a constructor. They are rarely used with destructors or with regular functions.

Function-try-block does not catch the exceptions thrown by the copy/move constructors and the destructors of the function parameters passed by value: those exceptions are thrown in context of the caller.

Function-try-block of the top-level function of a thread does not catch the exceptions thrown from the constructors and destructors of thread-local objects (except for the constructors of function-scoped thread-locals). (since C++11)

Likewise, function-try-block of the main() function does not catch the exceptions thrown from the constructors and destructors of static objects (except for the constructors of function-local statics).

The scope and lifetime of the function parameters (but not any objects declared in the function itself), extend to the end of the handler-sequence.

int f(int n = 2) try {
   ++n; // increments the function parameter
   throw n;
} catch(...) {
   ++n; // n is in scope and still refers to the function parameter
   assert(n == 4);
   return n;
}