Stack Unwinding

Whenever a exception is thrown, process of deallocating resources and calling destructors for objects starts on the stack, this is called stack Unwinding.

class Resource {
public:
    Resource() {
        std::cout << "Resource acquired\n";
    }

    ~Resource() {
        std::cout << "Resource released\n";
    }
};
void foo() {
    Resource res; // Resource acquired
    throw std::runtime_error("Error in foo");
}
int main() {
    try {
        foo();
    } catch (const std::runtime_error& e) {
        std::cerr << "Caught exception: " << e.what() << std::endl;
    }
    return 0;
}                            
                    
How Stack unwinding works
- foo() is called, it acquires a Resource object
- it then throws a std::runtime_error exception.
- As a result, the stack starts unwinding, and the destructor for res is called to release the Resource
- Then, exception is caught in the main() function.
- This ensures that resources are properly cleaned up even in the presence of exceptions.

Stack Unwinding has runtime overhead
- When there are deeply nested function calls or objects with complex destructors, it will take time to deallocate the object.
- How RUST removes this overhead

Runtime Type Information (RTTI)

RTTI means performing dynamic type checking and type casting at runtime.

1. Increased Binary size with RTTI
When RTTI is enabled, the compiler includes additional metadata in the binary to support dynamic type information.
This metadata typically includes:
- type information tables (type descriptors)
- virtual function tables (vtables) used for dynamic dispatch etc
These tables increase the size of the binary, especially for programs with a large number of polymorphic classes.
2. Increased Execution time with RTTI
2.1 Dynamic Casts
Dynamic casts (dynamic_cast) involve runtime type checking to ensure the correctness of the cast. This type checking adds overhead to the execution time of the program.
2.2 Virtual Function Calls
Dynamic polymorphism in C++ works on virtual function calls, which require runtime lookup of the appropriate function. This lookup incurs additional runtime overhead compared to static dispatch

#include 
#include 

class Base {
public:
    virtual ~Base() {}
};

class Derived : public Base {};

int main() {
    Base* ptr = new Derived();
    Derived* derived = dynamic_cast(ptr);
    if (derived) {
        std::cout << "Dynamic cast successful\n";
    } else {
        std::cout << "Dynamic cast failed\n";
    }
    delete ptr;
    return 0;
}