What is Exception

Exception is the problem state into which program enters that's not normal. Now exception floats into callstack until handler is found for it.
if Handler is found (ie appropriate catch then ok) else std::terminate is invoked and the program exits.
Examples of exception:
- Divide by Zero.
- Accessing out of bound array index. //Segmentation Fault and abort.
But we can place the same code inside try, catch and do something so that program does no coredumps.

try, throw, catch

In case of problem instead of simply dying(std::terminate, coredump), transfer control from one part of a program to another. This is build on 3 keywords:
1. try block: This need to be protected
2. throw keyword: Instead of dying, throw exception that should be handled in some other part of code
3. catch: This catches the thrown exception. This is piece of code that executes on thrown Exception.

Examples

Divide by 0


int main() {
    int a = 0;
    try {                             //Protected Code
        if (a == 0)
            throw runtime_error("Divide by 0");
        int b = 1/a;
    }
    catch (runtime_error& e) {
        cout << "runtime error:" << e.what();
    } catch (...) {
        cout << "Exception";
    }
}
    

numeric_limits


void MyFunc(int c) {
    if (c > numeric_limits<char>::max()) {
        throw invalid_argument("MyFunc argument too large.");
    }
}

int main() {
    try {
        MyFunc(256); //cause an exception to throw
    }
    catch (invalid_argument& e) {
        cerr << e.what();
        return -1;
    }
    return 0;
}
        

Exception in Constructor


class base {
    char* ptr;
public:
base() {
    ptr = nullptr;
    ptr = new char[10];
    if (ptr == nullptr) 
        throw std::bad_alloc();        //Exception thrown from constructor
}
~base(){
    std::cout << "base dtr\n";
}
};
int main() {
    try {
        base b;
    }
    catch (std::bad_alloc& b) {
        std::cout << "Bad alloc" << b.what();
    }
    catch(...){
        std::cout << "Exception happened";
    }    
}
        

Exception class

Exception class is used to create our own exception types.
Why own exception types are needed?
1. We want to display custom message to user at time of exception.
2. Perform some logging on Log server. Block security sensitive information from being dumped. An exception might contain sensitive information, we donot want to show this to user.

Empty Exception class

a. In try block we throw OBJECT of class type
b. catch, catches the object and displays it

class demo {};
int main() {
    try {
        throw demo();                   //a
    }
    catch (demo d) {                  //b
        cout << "Caught exception of demo class \n";
    }
}
        

Exception class having what() method


class BadLength {
    int a;
public:
    BadLength(int x):a(x){}
    int what(){
        return a;
    }
};
int main() {
    int len;
    cin >> len;
    try {
        if (len < 5)
            throw BadLength(len);             //1. Call constructor of class
        else
            cout << "Len is Fine";
    } catch (BadLength b) {
        cout << "Too Short:" << b.what();
    }
}
        

NULLException class

1. Create a class called NULLException. This class will: Log message to Log server, print custom information with Exception message
2. Throw the custom class.
3. Catch the custom class.

////////////Example//////////////////
class NULLException { ... }
main ()
    try {
        throw NULLException;
    } catch (NULLException obj) {
        cout << obj.what ();
    } catch (...) {               //This will not be executed
    }

/////////////////Code////////////////
class base {
protected:
    char* m_msg = nullptr;
private:
    void copyMsg (const char *test) {       //Deep copy
        char *customMessage = "Amit ";                      //Added Custom Message
        if ( test != nullptr ) {
            delete [] m_msg;
            m_msg = nullptr;
        }
        size_t size = strlen (test);
        m_msg = new char [size+6];
        memset (m_msg, '\0', size);

        memcpy (m_msg, customMessage, 5);
        memcpy ((char*)m_msg+5, test, size);                      //3
    }

public:
    base (const char* m) : m_msg(nullptr) { //Default ctr doing deep copy
        copyMsg (m);
        cout << "Logged message on Log server\n";
    }
    base (const exception& obj) {         //copy ctr doing deep copy
        copyMsg (obj.what());
    }
    base& operator = (const base& obj) {    //Assigment operator deep copy
    if (this != &obj)
        copyMsg(obj.what());
    }
    virtual ~base() {                     //Destructor
    if ( nullptr != m_msg) {
        delete [] m_msg;
        m_msg = nullptr;
    }
    }
    virtual const char* what() const {
    return m_msg;
    }
};

class NULLException : public base {
public:
    explicit NULLException (const char *msg) : base (msg) {}
};

int main() {
    try {
    char *ptr = nullptr;

    if (ptr == nullptr)
        throw NULLException ("NULL Exception");

    } catch (const NULLException &obj ) {
    printf ("%s\n",__FILE__);                       //2
    cout < obj.what();                     //3
    } catch (...) {
    cout << "Catch ellipse block";                  //Will not executed
    }
}
/*Output
Logged message on Log server                  //1
filename.cpp                                  //2 
Amit Null Exception                           //3