Function try blocks

You may decide that you want to protect an entire function with a try block, in which case you could write code like this:

    void test(double d) 
{
try
{
cout << setw(10) << d << setw(10) << reciprocal(d) << endl;
}

catch (exception& e)
{
cout << "error: " << e.what() << endl;
}
}

This uses the reciprocal function, as defined earlier, that will throw an exception if the parameter is zero. An alternative syntax for this is:

    void test(double d) 
try
{
cout << setw(10) << d << setw(10) << reciprocal(d) << endl;
}
catch (exception& e)
{
cout << "error: " << e.what() << endl;
}

This looks rather odd because the function prototype is followed immediately by the try... catch block and there is no outer set of braces. The function body is the code in the try block; when this code completes the function returns. If the function returns a value, it must do it in the try block. In most cases, you will find that this syntax makes your code less readable, but there is one situation where it may be useful--for initializer lists in constructors.

    class inverse 
{
double recip;
public:
inverse() = delete;
inverse(double d) recip(reciprocal(d)) {}
double get_recip() const { return recip; }
};

In this code, we wrap a double value that is simply the reciprocal of the parameter passed to the constructor. The data member is initialized by calling the reciprocal function in the initializer list. Since this is outside of the constructor body, an exception that occurs here will be passed straight to the code that calls the constructor. If you want to do some additional processing, then you could call the reciprocal function inside the constructor body:

    inverse::inverse(double d)  
{
try { recip = reciprocal(d); }
catch(exception& e) { cout << "invalid value " << d << endl; }
}

It is important to note that the exception will be automatically rethrown because any exception in a constructor means that the object is invalid. However, this does allow you to do some additional processing, if necessary. This solution will not work for exceptions thrown in a base object constructor because, although you can call a base constructor in the derived constructor body, the compiler will call the default constructor automatically. If you want the compiler to call a constructor other than the default constructor you have to call it in the initializer list. An alternative syntax to providing exception code in the inverse constructor is to use function try blocks:

    inverse::inverse(double d)  
try
: recip (reciprocal(d)) {}
catch(exception& e) { cout << "invalid value " << d << endl; }

This looks a little cluttered, but the constructor body is still after the initializer list giving an initial value to the recip data member. Any exception from the call to reciprocal will be caught and automatically rethrown after processing. The initializer list can contain calls to the base class and any of the data members and all will be protected with the try block.