Error Handling

Errors in code can be the result of a programmer’s mistake (i.e. a bug) or they can occur at runtime due to invalid input, system errors, and so forth. For degugging, C++ uses the assert statement. For runtime errors, we can try something and handle the result if a problem occurs.

Exceptions

Runtime errors may include

  • An attempt to read a file that isn’t present
  • A floating-point exception due to invalid input to a function
  • A divide-by-zero floating-point exception and so forth.

All these conditions (and many more) are called exceptions. If the programmer does not handle them, execution will stop

Catching Exceptions

The “dangerous” section of code is enclosed in a try block. If an error occurs within it, an exception will be thrown so we can catch it.

try {
  if (y != 0) {
    float z=x/y;
  } else {
    throw 10;
  }
}
catch (int e) {
    cout << "An exception occurred, error "<<e<<"\n";
}

Exceptions can be stacked

try {
   //code, throw things
}

catch (int e) { cout << "Integer exception \n"; }
catch (char c){ cout << "Character exception \n";}
}

Generic Exceptions

If we do not know what type of exception might occur, we can replace the paraneters to catch with an elipsis ...

try {
    if (y != 0) {
        float z=x/y;
    }
    else {
        throw "Exception";
    }
}
catch (...) {
   cout << "An exception occurred\n";
}

Standard Exceptions

The C++ standard includes a base class for exceptions. The exception header must be included. The programmer can derive custom exceptions, or use the built-in set provided by this class. Some of the more commonly-seen ones are:

Exception Cause
std::bad_alloc Can’t allocate memory
std::invalid_argument Invalid argument to function
std::length_error String too long
std::out_of_range Can be thrown by at operator (vector etc.)
std::overflow_error Numerical overflow error
std::underflow_error Numerical underflow error

See the documentation for more information.

try {
   cout << "Last item "<<v.at(6)<<endl;
}
   catch (const out_of_range &e) {
   cout << "Out of range \n";
}

Exercise Assemble the example snippets into a working program.

Example

#include <iostream>
#include <vector>
#include <exception>

using namespace std;

int main() {
    float x=10.;
    float y=0.;
    try { 
        if (y != 0) {
	    float z=x/y;
        } else {
            throw 10;
        }
    }
    catch (int e) {
       cout << "An exception occurred, error "<<e<<"\n";
    }

    try {
        if (y != 0) {
	    float z=x/y;
        }
	else {
	    throw "Exception";
        }
    }
    catch (...) {
       cout << "An exception occurred\n";
    }

    vector<double> v{1.,2.,3.,4.,5.};

    try {
      cout << "Last item "<<v.at(6)<<endl;
    }
    catch (const out_of_range &e) {
       cout << "Out of range \n";
    }
}



Assert

The assert statement is used to check for conditions that should not happen at all. It is primarily used for debugging or quality assurance, not routine error handling. The assertions in a program are typically disabled for production versions.

#include <cassert>

<code>
assert(conditional);

Example

assert(x != 0);

To disable assert statements, use the NDEBUG flag.

#include <cassert>
#define NDEBUG

A common practice is to define NDEBUG for debugging, then comment it out and recompile for the production executable.

Static Assertions (C++11)

The assert statement is executed at runtime. C++11 introduces the static_assert statement, which is evaluated at compile time.

static_assert (const_bool);

One example of how static_assert may be helpful is checking for the size of certain types. For instance, the C++ standard does not require a specific size for int, just a minimum. The exact size may be platform-dependent. The statement

sizeof(type) * CHAR_BIT

evaluates to the number of bits in type on the compiling platform. If, for instance, we need to be sure that int is 32 bits, we can use static_assert

static_assert(sizeof(int) * CHAR_BIT == 32);

The CHAR_BIT macro is in the C limits.h header.

Exercise

Run the following code as is on your platform. Change the number of bits to make the assertion pass or fail.

Example

#include <iostream>
#include <climits>

int main() {
  
    static_assert(sizeof(long) * CHAR_BIT == 32);

}

Previous
Next