Exceptions provide a way to handle errors or exceptional conditions in a program. They allow you to separate error-handling code from regular code, making your programs easier to read and maintain.
try
{
// Statements that may throw exceptions you want to handle go here
throw -1; // here's a trivial throw statement
}
catch (int x)
{
// Handle an exception of type int here
std::cerr << "We caught an int exception with value " << x << '\n';
}
try
block must have at least one catch
block immediately following it, but may have multiple catch
blocks listed in sequence.catch (...) // catch-all handler
{
std::cerr << "We caught an exception of unknown type";
}
You can create classes primarily used to handle exceptions.
class ArrayException
{
private:
std::string m_error;
public:
ArrayException(std::string_view error)
: m_error{ error }
{
}
const std::string& getError() const { return m_error; }
};
Handlers for derived exception classes should be listed before those for base classes.
std::exception
(defined in the <exception>
header) is a small interface class designed to serve as a base class to any exception thrown by the C++ standard library.
catch (const std::exception& exception)
{
std::cerr << "Standard exception: " << exception.what() << '\n';
}
Throwing a standard exception:
throw std::runtime_error("Invalid index");
The noexcept
specifier means the function promises not to throw exceptions itself.
void doSomething() noexcept; // this function is specified as non-throwing
throw
keyword by itself.Use function try blocks when you need a constructor to handle an exception thrown in the member initializer list.
class B : public A
{
public:
B(int x) try : A{x} // note addition of try keyword here
{
}
catch (...) // note this is at the same level of indentation as the function itself
{
// Exceptions from member initializer list or constructor body are caught here
std::cerr << "Exception caught\n";
throw; // rethrow the existing exception
}
};
Ways to ensure that dynamic memory in try blocks will be deallocated if an error occurs:
std::unique_ptr
.auto* john { new Person("John", 18, PERSON_MALE) };
std::unique_ptr<Person> upJohn { john }; // upJohn now owns john
Destructors should not throw exceptions.
Exceptions are best used when all of the following are true:
noexcept
.noexcept
when you can.noexcept
on other functions to express a no-fail or no-throw guarantee.std::move_if_noexcept
will return a movable r-value if the object has a noexcept
move constructor, otherwise it will return a copyable l-value.
Exceptions provide a way to handle errors or exceptional conditions in a program. They allow you to separate error-handling code from regular code, making your programs easier to read and maintain.