C++ PROGRAMMING

Exceptions

Article by:
Date Published:
Last Modified:

Overview

Exceptions are a supported form of error handling in C++. They allow the code write to throw and catch exceptions which can propagate through the call stack.

Note that it is common practice to use e to represent a variable that is of an exception type.

C++ is one of the “lowest level” languages that supports exceptions. Other low-level languages such as C do not have exception support.

Notation

1
2
3
4
5
try {
	// Do error-prone stuff here
} catch(exception_type exception) {
	// Catch an exception of type exception_type here
}

How The Exceptions Work

The Standard Exceptions

std::exception doesn’t support an additional message (it doesn’t have an e.what()).

The standard exceptions are defined in <stdexcept>. They are split into categories:

Logic Errors

ExceptionDescription
domain_error
invalid_argument
length_error
logic_error
out_of_range

Runtime Errors

ExceptionDescription
overflow_error
range_error
runtime_errorUse std::runtime_error for general errors that occur in the running of your program.
underflow_error

My Exception Message (e.what() Is Not Saying The Right Thing!

The most common reason for this is that you have forgotten to catch by reference (&)! Make sure that your catch statement looks like this:

1
catch(std::exception& e) {}

and not like this:

1
catch(std::exception e) {}

Remember, the standard rule for exceptions in C++ is:

throw by value, catch by reference

C++11 Additions

C++11 added new exception types to the standard library.

One is the std::system_error. It inherits from std::runtime_error. It is typically thrown by functions which interact with the operating system. It has two members, the standard what(), and a new code(). Calling code() returns the error code associated with the error.

Here is an example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <thread>
#include <iostream>
#include <system_error>

int main() {
	try {
		std::thread().detach(); // attempt to detach a non-thread
	}	catch(const std::system_error& e)	{
		std::cout << "Caught system_error with code " << e.code() 
		<< " meaning " << e.what() << '\n';
	}
}

Notice that the error_code object returns by code() can be inserted into a ostream.

This new system_error object with the additional code() method presents problems when using the standard catch, as other exceptions do not have this method. You can either write two separate catch statements (my preferred method).

1
2
3
4
5
6
7
try {}
catch (const std::system_error& e) {
    std::cout << e.what() << '\n';
    std::cout << e.code() << '\n';
} catch (const std::exception& e) {
    std::cout << e.what() << '\n'; 
}

Or you can use a dynamic_cast like below.

1
2
3
4
5
6
7
try {}
catch (const std::exception& e) {
	std::cout << e.what() << '\n';
	auto se = dynamic_cast<const std::system_error*>(&e);
	if(se != nullptr)
		std::cout << se->code() << '\n';
}

The noexcept Keyword

The noexcept keyword was added to the C++ language in C++11. It can used to specify a function which is guaranteed to not throw an exception.

1
void example() noexcept;

The above declaration states that example() is a function which does not throw an exception.

The compiler treats all C++ functions as either non-throwing or potentially-throwing.

noexcept can be also be passed a boolean, passing in true to state that the function is non-throwing or false to state that it is potentially throwing.

1
2
void example1() noexcept(true); // example1() is non-throwing
void example2() noexcept(false); // example2() is potentially-throwing

Why Use noexcept?

So why use noexcept? One on the primary reasons for using noexcept is so that the compiler can perform certain optimizations it wouldn’t otherwise be able to do. A common example of this is the std::move_if_noexcept() function, which can be used in the implementation of things such a std::vector<T>::push_back(). If the compiler is able to determine that a function is non-throwing, it can use move operations instead of copy operations, which usually leads to performance increases.

What Happens If I Throw Inside A Function Declared noexcept?

The compiler doesn’t actually guarantee that exceptions are not thrown in a non-throwing function. However, the behaviour of an exception thrown inside a function declared as noexcept is changed. Instead of the exception propagating up the call stack to the nearest applicable catch block, std::terminate() is called.

WARNING

Do not get noexcept confused with std::nothrow. noexcept is a C++ language keyword as explained above, while std::nothrow is a constant that can be passed into the new operator.


Authors

Geoffrey Hunter

Dude making stuff.

Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License .

Tags

    comments powered by Disqus