9

just a quick question. Is there any difference between

void f(Foo x) try
{
   ...
}
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 ?

Alexandre C.
  • 55,948
  • 11
  • 128
  • 197

5 Answers5

10

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.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • 5
    Which means that function try blocks for non-constructor functions are JUST an alternative syntax, no semantic purposes, which may indeed be an arguable argument for their existence. On the other hand, there are far too many inexplicable things in C++, even among those which have nothing to do with compatibility. – Armen Tsirunyan Oct 08 '10 at 11:09
  • The first paragraph is wrong. You forgot about destructors. – Quirin F. Schroll Aug 31 '22 at 12:04
6

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.

MSalters
  • 173,980
  • 10
  • 155
  • 350
1

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)

davka
  • 13,974
  • 11
  • 61
  • 86
  • 1
    ...unless the "catch" block itself unconditionally throws or re-throws, in which case the function try block is the cleanest way to write this, IMO. – Nemo Mar 16 '16 at 00:24
  • 2
    (Comment is added 5 years later:) I tested with gcc 5.4 -- There, I can return a value from the catch-block. However, I did not study any standards. – ralfg Aug 24 '16 at 07:40
  • 1
    This answer is wrong and AFAIK was so already at the time of creation, see [here](http://en.cppreference.com/w/cpp/language/function-try-block), in particular the example at the bottom. – Walter Aug 24 '16 at 08:12
  • 2
    I tested if we can return from catch handler of a function try block on a non-void function; I was able to. But as per the cppreference entry this is undefined behavior. – anurag-jain Jul 03 '17 at 08:25
  • 1
    This answer should be deleted. It is plain wrong. – Quirin F. Schroll Aug 31 '22 at 11:48
1

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.

Ferruccio
  • 98,941
  • 38
  • 226
  • 299
  • which doesn't solve the problem of static/global objects of potentially-throwing-in-constructor classes, because the exception is rethrown anyway. – Armen Tsirunyan Oct 08 '10 at 11:11
  • 3
    @Armen: Constructors _have_ to throw if the object cannot be initialized. This is the _only_ way to report construction failure. – Alexandre C. Oct 08 '10 at 11:15
  • Also for catching exceptions thrown by **de**structors of non-static data members when the **de**structor runs. Less common use-case, but could not be done with a regular try-catch in the destructor. – Quirin F. Schroll Aug 31 '22 at 11:51
0

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.

Quirin F. Schroll
  • 1,302
  • 1
  • 11
  • 25