How are errors reported in code?
What behavior is considered erroneous?
"a function couldn’t do what it advertised"
What behavior is considered erroneous?
arguments
state
do the job
side effects
result value
What behavior is considered erroneous?
arguments
state
do the job
side effects
result value
arguments
do the job
result value
What behavior is considered erroneous?
arguments
state
do the job
side effects
result value
Invalid Operation
Invalid Argument
Runtime Error
Out of Memory
What behavior is considered erroneous?
Implementation Error
arguments
state
do the job
side effects
result value
Invalid Operation
Invalid Argument
arguments
state
do the job
side effects
result value
Invalid Operation
Invalid Argument
What behavior is considered erroneous?
Runtime Error
Out of Memory
Runtime Error
Out of Memory
Implementation Error
Implementation Error
What behavior is considered erroneous?
Invalid Operation
Invalid Argument
Runtime Error
Out of Memory
Implementation Error
out of bounds access, null pointer dereference, division by zero
pop from empty stack, write to immutable object, race condition
heap exhaustion
stack overflow, hardware failure, cannot open file, operating system complaint
not yet implemented, bug
How are errors reported in code?
What behavior is considered erroneous?
How are errors reported in code?
Termination
UB
abort assert
Invalid Operation
Invalid Argument
Implementation Error
Out of Memory
Runtime Error
Error codes
Exceptions
errno error_code
std::exception try, throw, catch noexcept
Out of Memory
Runtime Error
*Invalid Operation
*Invalid Argument
Exception
InvalidOperationException
ArgumentException
IndexOutOfRangeException
NullReferenceException
StackOverflowException
OutOfMemeoryException
DivideByZeroException
exception
UB or logic_error
UB, assert, logic_error
UB, assert, logic_error
UB, assert, logic_error
UB
UB, bad_alloc
UB, assert
ill-formed
ill-formed; no diagnostic required (NDR)
undefined behavior (UB)
implementation defined behavior
unspecified behavior
Compile-time
Run-time
bool p;
if (p)
{
std::cout << "p";
}
if (!p)
{
std::cout << "!p";
}
bool will_increment_overflow(int x)
{
if (x + 1 < x)
{
return true;
}
return false;
}
bool will_increment_overflow(int x)
{
return false;
}
p!p
bool p = init_val();
if (p)
{
std::cout << "p";
}
if (!p)
{
std::cout << "!p";
}
bool will_increment_overflow(int x)
{
return x == std::numeric_limits<int>::max();
}
assert(condition)
static_assert(condition, message)
static_assert(condition)
condition
Invalid Operation
Invalid Argument
Implementation Error
std::exit
std::quick_exit
std::_Exit std::terminate std::abort
std::atexit std::at_quick_exit - std::terminate_handler std::signal
- - - std::abort() -
function
handler
default handler
Exit Codes
EXIT_SUCCESS
EXIT_FAILURE
<cstdlib>
<cstdlib>
<cstdlib>
<cstdlib>
<exception>
<cstdlib>
[[noreturn]]
[[noreturn]] void Panic(std::string msg)
{
std::cerr << "Fatal error occured: " << msg;
std::abort();
}
Out of Memory
Runtime Error
void try_process_names()
{
file_t f;
int err = try_open_file("names.txt", &f);
if (err == FILE_ERROR)
{
std::cerr << "Cannot open file";
}
else
{
process(f);
}
}
int try_open_file(const char* path, file_t* t)
{
os_file_t* native_file = os_open_file(path);
if (os_file_t)
{
(*t) = wrap_native_file(native_file);
return NO_ERROR;
}
else
{
return FILE_ERROR;
}
}
errorCodeType readFile {
initialize errorCode = 0;
open the file;
if (theFileIsOpen) {
determine the length of the file;
if (gotTheFileLength) {
allocate that much memory;
if (gotEnoughMemory) {
read the file into memory;
if (readFailed) {
errorCode = -1;
}
} else {
errorCode = -2;
}
} else {
errorCode = -3;
}
close the file;
if (theFileDidntClose && errorCode == 0) {
errorCode = -4;
} else {
errorCode = errorCode and -4;
}
} else {
errorCode = -5;
}
return errorCode;
}
readFile {
try {
open the file;
determine its size;
allocate that much memory;
read the file into memory;
close the file;
} catch (fileOpenFailed) {
doSomething;
} catch (sizeDeterminationFailed) {
doSomething;
} catch (memoryAllocationFailed) {
doSomething;
} catch (readFailed) {
doSomething;
} catch (fileCloseFailed) {
doSomething;
}
}
from (Oracle Java Tutorials)
errorCodeType readFile {
initialize errorCode = 0;
open the file;
if (theFileIsOpen) {
determine the length of the file;
if (gotTheFileLength) {
allocate that much memory;
if (gotEnoughMemory) {
read the file into memory;
if (readFailed) {
errorCode = -1;
}
} else {
errorCode = -2;
}
} else {
errorCode = -3;
}
close the file;
if (theFileDidntClose && errorCode == 0) {
errorCode = -4;
} else {
errorCode = errorCode and -4;
}
} else {
errorCode = -5;
}
return errorCode;
}
readFile {
try {
open the file;
determine its size;
allocate that much memory;
read the file into memory;
close the file;
} catch (fileOpenFailed) {
doSomething;
} catch (sizeDeterminationFailed) {
doSomething;
} catch (memoryAllocationFailed) {
doSomething;
} catch (readFailed) {
doSomething;
} catch (fileCloseFailed) {
doSomething;
}
}
from (Oracle Java Tutorials)
void process_names()
{
try
{
file f = open_file("names.txt");
process(f);
}
catch(const std::exception& e)
{
std::cerr << e.what();
}
}
file_t open_file(const char* path)
{
os_file_t* native_file = os_open_file(path);
if (os_file_t)
{
return wrap_native_file(native_file);
}
else
{
throw std::runtime_error("Cannot open file");
}
}
void f() {
throw std::runtime_error();
}
void g() { f(); }
void h() { f(); }
void i() {
try {
h();
}
catch(const std::runtime_error& e) {
...
}
}
throw std::runtime_error();
throw 5;
throw "Hello world";
catch(...) {}
throw;
void f()
try {
}
catch (...) {
}
void f() {
try {
}
catch (const std::ios_base::failure& e) {
}
catch (const std::runtime_error& e) {
}
catch (const std::exception& e) {
}
catch (...) {
}
}
Database
entry
find(key)
entry* find(const std::string& key) noexcept;
bool find(const std::string& key, entry& out) noexcept;
entry find(const std::string& key); // throw if not found
entry find(const std::string& key) noexcept; // assume that key is valid, ub if not found
struct result_t
{
entry result;
bool has_result;
}
result_t find(const std::string& key) noexcept;
#include <optional>
std::optional<entry> find(const std::string& key) noexcept;
void useFind() {
auto result = find("Bob");
if (result) {
std::cout << "Bob has been found!";
std::cout << "Bob's data is" << *result;
}
if (result.has_value()) {
std::cout << "Bob has been found!";
std::cout << "Bob's data is" << result.value();
}
if (!result) {
std::cout << *result; // UB
std::cout << result.value(); // throw std::bad_optional_access
}
if (result == std::nullopt) {
std::cout << result.value_or("Bob not found");
}
}