Unit 6 - Notes

CSE202

Unit 6: Exception Handling, Templates and Standard Template Library (STL)

1. Basics of Exception Handling

Exception handling provides a way to transfer control from one part of a program to another. It is an error-handling mechanism built into C++ to handle runtime errors (anomalies) such as division by zero, array index out of bounds, or running out of memory.

Key Concepts

  • Exception: An abnormal condition that arises in a code sequence at runtime.
  • Synchronous Exceptions: Errors that occur during the execution of instructions (e.g., out of range index, overflow).
  • Asynchronous Exceptions: Errors caused by events beyond the control of the program (e.g., keyboard interrupt, disk failure). C++ Exception handling mainly deals with synchronous exceptions.
  • Purpose: To separate error-reporting code from error-handling code, making the software more robust and easier to maintain.

2. Exception Handling Mechanism

C++ uses three keywords to perform exception handling: try, catch, and throw.

  1. Try Block (try): Used to wrap code that might throw an exception.
  2. Throw (throw): Used to signal that an exception has occurred.
  3. Catch Block (catch): Used to handle the exception thrown by the try block.

Basic Syntax

CPP
try {
    // Code that may raise an exception
    if (error_condition) {
        throw exception_variable;
    }
}
catch (type variable) {
    // Code to handle the exception
}

Stack Unwinding

When an exception is thrown, the runtime system searches for the nearest enclosing catch block. If the current function does not handle it, the function terminates, and the system checks the caller function. This process of popping stack frames to find a handler is called Stack Unwinding. During this process, destructors for local objects are called automatically.


3. Throwing Mechanism

The throw keyword is used to explicitly raise an exception. You can throw primitive types (int, char, float) or user-defined objects.

Throwing Primitive Types

CPP
int divide(int a, int b) {
    if (b == 0) {
        throw 404; // Throwing an integer error code
    }
    return a / b;
}

Throwing Objects

It is best practice to throw objects (often derived from std::exception) to convey more information.

CPP
class DivideByZeroError {}; // Empty class for exception tagging

if (b == 0) {
    throw DivideByZeroError(); // Throwing an object
}


4. Catching Mechanism

The catch block follows immediately after a try block. A single try block can have multiple catch blocks to handle different types of exceptions.

Multiple Catch Blocks

CPP
try {
    // code
}
catch (int e) {
    cout << "Integer exception: " << e;
}
catch (char c) {
    cout << "Character exception: " << c;
}
catch (MyException& e) {
    cout << "Object exception";
}

Catch-All Handler (...)

To catch any type of exception that is not handled by previous catch blocks, C++ provides the ellipsis syntax. This must be the last catch block.

CPP
catch (...) {
    cout << "Default exception handler: Unknown error occurred.";
}

Catching Base and Derived Classes

If catching exceptions of a class hierarchy, Derived class handlers must appear before Base class handlers. If the Base catch block comes first, it will catch both Base and Derived objects, making the Derived handler unreachable.


5. Rethrowing an Exception

Sometimes a catch block processes an exception partially but cannot handle it completely. In such cases, it can rethrow the exception to be handled by the caller function.

Syntax

CPP
void myFunction() {
    try {
        throw 20;
    }
    catch (int e) {
        cout << "Partially handled in myFunction." << endl;
        throw; // Rethrows the current exception to the outer scope
    }
}

int main() {
    try {
        myFunction();
    }
    catch (int e) {
        cout << "Caught rethrown exception in main: " << e << endl;
    }
}


6. Templates (Generic Programming)

Templates allow functions and classes to operate with generic types. This allows code reusability for different data types without rewriting code.

Function Templates

A function template defines a family of functions.
Syntax:

CPP
template <typename T>
T myMax(T x, T y) {
    return (x > y) ? x : y;
}

Usage:
CPP
int i = myMax(10, 20);       // T becomes int
double d = myMax(5.5, 2.1);  // T becomes double

Multiple generic types are allowed: template <class T1, class T2>.

Class Templates

A class template defines a family of classes. Common examples include generic Stack, Linked List, etc.

Syntax:

CPP
template <class T>
class Box {
    T item;
public:
    Box(T i) : item(i) {}
    T getItem() { return item; }
};

Usage:
CPP
Box<int> intBox(123);
Box<string> strBox("Hello");


7. Class Template with Inheritance

Templates can be combined with inheritance in three primary ways:

  1. Deriving a Class Template from a Class Template:
    Both Base and Derived are templates.

    CPP
        template <class T>
        class Base { ... };
    
        template <class T>
        class Derived : public Base<T> { ... };
        

  2. Deriving a Class Template from a Non-Template Class:
    Base is normal, Derived is generic.

    CPP
        class Base { ... };
    
        template <class T>
        class Derived : public Base { ... };
        

  3. Deriving a Non-Template Class from a Class Template (Specialization):
    The derived class must specify the type for the base template.

    CPP
        template <class T>
        class Base { ... };
    
        class Derived : public Base<int> { ... };
        


8. Introduction to STL (Standard Template Library)

The STL is a set of C++ template classes to provide common programming data structures and functions. It consists of three main components:

1. Containers

Objects that hold data. They manage the storage space for their elements and provide member functions to access them.

  • Sequence Containers: Store elements in a linear fashion (e.g., Vector, List, Deque).
  • Associative Containers: Store elements in sorted order (e.g., Set, Map).
  • Unordered Containers: Store elements using hash tables (e.g., Unordered_map).
  • Container Adapters: Interface restrictions (e.g., Stack, Queue).

2. Algorithms

A collection of functions designed to be used on ranges of elements. They act on containers.

  • Header: <algorithm>
  • Examples: sort(), reverse(), search(), count(), binary_search().

3. Iterators

Objects that point to an element in a container. They act as a bridge between algorithms and containers. They function similarly to pointers.

  • Syntax: ContainerType::iterator iterName;
  • Operations: *iter (access), iter++ (next), begin() (start), end() (past the last element).

9. Container - Vector

A std::vector is a dynamic array that can resize itself automatically when an element is inserted or deleted.

  • Header: <vector>
  • Memory: Elements are stored in contiguous memory locations.
  • Access: Supports direct random access (O(1)).

Common Functions

  • push_back(val): Adds element to the end.
  • pop_back(): Removes the last element.
  • size(): Returns the number of elements.
  • capacity(): Returns the size of storage space currently allocated.
  • at(index): Returns element at index (with bounds checking).
  • clear(): Removes all elements.

Example

CPP
#include <vector>
#include <iostream>
using namespace std;

int main() {
    vector<int> v;
    
    v.push_back(10);
    v.push_back(20);
    
    // Using iterator
    vector<int>::iterator it;
    for(it = v.begin(); it != v.end(); it++) {
        cout << *it << " ";
    }
    return 0;
}


10. Container - List

A std::list is a doubly linked list. Unlike vectors, elements are not stored in contiguous memory.

  • Header: <list>
  • Memory: Non-contiguous.
  • Access: Sequential access only (O(n)). No [] operator or .at().
  • Efficiency: Fast insertion and deletion anywhere in the list (O(1) once the position is found).

Common Functions

  • push_back(val): Adds to end.
  • push_front(val): Adds to beginning.
  • pop_back(): Removes from end.
  • pop_front(): Removes from beginning.
  • sort(): Sorts the list elements.
  • reverse(): Reverses the list.
  • remove(val): Removes all elements with specific value.

Example

CPP
#include <list>
#include <iostream>
using namespace std;

int main() {
    list<int> l;
    
    l.push_back(10);
    l.push_front(5); // List is now: 5, 10
    
    l.sort(); // Sorting
    
    for(int x : l) {
        cout << x << " ";
    }
    return 0;
}

Comparison: Vector vs. List

Feature Vector List
Data Structure Dynamic Array Doubly Linked List
Memory Contiguous Non-Contiguous
Random Access Yes (Fast) No (Slow)
Insertion/Deletion (Middle) Slow (Requires shifting) Fast (Pointer manipulation)
Insertion (End) Fast (Amortized constant) Fast