foo::foo()
try
{
body:
//... do stuff that could possibly throw
}
catch(std::exception &e){
handler:
throw;
}
That piece of code has two rather unusual constructs. The first is what you already pointed out and has already been explained in mjk's answer: body
and handler
are labels. Labels are used for goto
s, and that in turn can be used for flow control (determining where the code should continue executing). Now, goto
s should rarely be used, as there are very few cases where they cannot be substituted by other flow controls (if
,for
,while
,do
...) that would make it more readable. Since goto
s are rarely used, labels are also rarely used.
The second interesting construct is the function-level try block:
foo::foo()
try {
} catch (std::exception const &) {
}
Note that there try
catch is not inside the constructor body, but actually outside the {}
. This is also a rare construct. It was designed to support catching an exception during the evaluation of the initializer list in the constructor (which in the code above is implicit). If the type has a base, or members whose constructors could throw, the constructor's body would never be evaluated and a regular try-catch would not be useful to treat that exception. The function level try block encloses also the initializer list and will catch any exception thrown during the evaluation of the different submember's constructors. It is a rarely used construct since you cannot really do much in the catch
block. The exact state of what has been or has not been constructed is unknown and cannot be verified so the only possible use is to rethrow either the same exception or a different one. The syntax in a more complete example would be:
T::T()
try
: base1(args), base2(), member1(), member2() //...
{
// body
} catch (exception1 const& ex1) {
// ...
throw; // rethrow same exception
} catch (exception2 const& ex2) {
// ...
throw different_exception();
}