When developing programs in C++, it's essential to handle exceptions that can occur during program execution. One way to handle these exceptions is by using function try blocks.
A function try-catch block is a special type of try-catch block that is used to catch exceptions thrown anywhere within the function that it is applied to. In this article, we will explain the basics of function try-catch blocks and show you how to use them in your code.
Previously, we have seen how we can have try
and catch
blocks inside a function:
#include <iostream>
#include <stdexcept>
void MyFunction() {
try {
throw std::runtime_error { "Oops!" };
} catch (std::runtime_error e) {
std::cout << e.what();
}
}
There is an alternative syntax for this, where we want the try
and catch
to apply to our whole function. It looks like this:
#include <iostream>
#include <stdexcept>
void MyFunction() try {
throw std::runtime_error { "Oops!" };
} catch (std::runtime_error e) {
std::cout << e.what();
}
As with regular try-catch blocks, we can have multiple catch
statements, to catch different types of errors:
#include <iostream>
#include <stdexcept>
void MyFunction() try {
throw std::runtime_error { "Oops!" };
} catch (std::logic_error e) {
std::cout << "Logic error!";
} catch (std::runtime_error e) {
std::cout << "Runtime error!";
}
Where the function has a non-void return type, all of the catch
statements will also need to respect that, by returning an appropriate object:
int GetNumber() try {
throw std::runtime_error { "Oops!" };
return 42;
} catch (std::runtime_error e) {
std::cout << e.what();
return -1;
}
Function try blocks are particularly useful when we want to catch exceptions within a class constructor. In the following example, line 13 is making a call to the Character
constructor, passing a value that is going to cause an exception.
But, how do we catch that exception within the Goblin
 constructor?
#include <iostream>
#include <stdexcept>
class Character {
public:
Character(int Health) {
if (Health < 0) throw std::logic_error {
"Health cannot be negative!"
};
}
};
class Goblin : Character {
public:
Goblin(int Health) : Character { Health } {
// How can we catch the error??
}
};
int main() {
Goblin MyChar { -100 };
}
Our program crashes without showing our error:
terminate called after throwing an instance of std::logic_error
When a member initializer list throws an exception, a function try block is the only way to catch that exception:
class Goblin : Character {
public:
Goblin(int Health) try : Character { Health } {
// How can we catch the error??
} catch (std::logic_error e) {
std::cout << e.what() << std::endl;
}
};
We now get our custom error message:
Health cannot be negative!
terminate called after throwing an instance of 'std::logic_error'
When an exception is thrown as part of a constructor, it is not possible to recover from that within the constructor. We just need to rethrow the error.
If we don’t rethrow the error, it will be implicitly rethrown for us, as indicated by the second line of our previous error log.
Therefore, the use of function try blocks within constructors has two purposes:
Comprehensive course covering advanced concepts, and how to use them on large-scale projects.