Function try blocks, but not in constructors
just a quick question. Is there any difference between
void f(Foo x) try开发者_StackOverflow
{
...
}
catch(exception& e)
{
...
}
and
void f(Foo x)
{
try { ... }
catch (exception& e)
{
...
}
}
?
If no, why are function try blocks for (the case of initialization lists for constructors being put aside) ? What happens if the copy constructor of Foo
throws an exception when x
is passed to f
?
Function try blocks are only ever needed in constructors. In all other cases exactly the same effect can be achieved by enclosing the entire body of the function in a normal try/catch block.
If the copy constructor used to initialize a parameter throws an exception this happens before the function call. It cannot be caught by a function try block or exceptional handler in the function as the function doesn't get called.
Some things are allowed because it would be harder to disallow them. Allowing function try blocks on some, but not all function bodies would make the grammar and compilers more complicated.
Function try blocks were added expressly for the purpose of catching exceptions in constructor initialization lists.
In your example there are no constructor initializations, so there is no difference between the two forms.
Just spotted an interesting point in this Dr. Dobb's article (although quite old):
...remember that you can't return a value inside a function-try-block handler. So it makes no sense to use a function try block for a non-void function
and this is their code example:
int f()
try
{
...
}
catch(Error &e)
{
// oops, can't return int from here!
}
Which actually means that function try blocks are weaker than "regular" try blocks and their use should be discouraged other than in constructors.
(the article is from 2000, so it'd be nice if someone would comment on whether this is still so in the current standard)
A function-try-block is equivalent to a try block inside the function spanning the whole function unless you have a constructor or destructor.
On a constructor, the function-try-block also catches exceptions thrown by constructors of your base classes and non-static data members. Catching those is not possible with a regular try block spanning the statement-block of the constructor. This is the primary use-case for function-try-block.
On a destructor, the function-try-block also catches exceptions thrown by destructors of base classes and your non-static data members. This cannot be achieved using a try block inside the destructor. Note that destructors that throw are bad design, nonetheless they are legal in C++ and this is the way to deal with them.
In both these cases, additional rules apply: You cannot use return
in the function-try-block’s catch
clauses of a constructor because a data member may not be properly constructed; however, you may use throw
and at the end of every catch
, there is an implicit throw;
statement. In a destructor’s function-try-block, at the end of every catch
, there is also an implicit throw;
, but an explicit return;
is allowed.
精彩评论