Open In App

Exception Handling & Templates Interview Questions - C++ Programming

Last Updated : 08 Aug, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

In modern C++, writing robust, reusable, and efficient code is key. Two important pillars that support this are:

  • Exception Handling: C++ supports a structured error-handling mechanism using:

try: block of code that may throw an exception
throw: used to raise an exception
catch: handles the thrown exception

  • Templates: Templates in C++ are a feature that allows you to write generic and reusable code. Instead of writing the same function or class multiple times for different data types (like int, float, double), you can use templates to create a single blueprint that works for any data type.

1. What happens when a constructor throws an exception in C++? Will the destructor of that object be called?

If a constructor throws an exception, the object is considered not fully constructed, and its destructor is not called. However, destructors of already fully constructed sub-objects or members will be called. This behavior ensures proper resource cleanup during object construction failure.

Example:

C++
#include <iostream>
using namespace std;

class A {
public:
    A() { cout << "A Constructor\n"; throw runtime_error("Error in A"); }
    ~A() { cout << "A Destructor\n"; }
};

class B {
public:
    B() { cout << "B Constructor\n"; }
    ~B() { cout << "B Destructor\n"; }
};

int main() {
    try {
        B b;  // Constructed successfully
        A a;  // Throws exception
    } catch (...) {
        cout << "Caught exception\n";
    }
    return 0;
}

2. What are templates in C++? Explain their importance.

Templates in C++ are a powerful feature that allows the creation of generic functions and classes. Instead of writing multiple versions of a function or class for different data types (e.g., int, float, double), templates let you write a single version that works for any type. Templates increase code reusability, reduce duplication, and are type-safe. They are widely used in the Standard Template Library (STL) for generic data structures like vector, stack, etc.

Example:

C++
template <typename T>
T add(T a, T b) {
    return a + b;
}

This function works for int, float, and other types that support the + operator.

3. What are standard exceptions in C++? List some common types.

C++ provides a hierarchy of standard exceptions in the <exception> and <stdexcept> headers. These are predefined classes derived from the base class std::exception and can be used to represent common errors.

Some commonly used standard exceptions:

  • std::exception – Base class for all exceptions
  • std::bad_alloc – Thrown when memory allocation fails (new)
  • std::out_of_range – For invalid array or container indexing
  • std::runtime_error – Represents errors at runtime
  • std::invalid_argument – For invalid function arguments
  • std::length_error, std::overflow_error, etc.

Example:

C++
#include <stdexcept>

throw std::out_of_range("Index is out of range");

Using standard exceptions makes your code consistent and compatible with STL and third-party libraries.

4. How do you create a custom exception in C++? Give an example.

You can create a custom exception by defining a class that inherits from the std::exception class and overriding its what() method, which returns an error message.

Example:

C++
#include <iostream>
#include <exception>
using namespace std;

class MyException : public exception {
public:
    const char* what() const noexcept override {
        return "Custom Exception Occurred";
    }
};

int main() {
    try {
        throw MyException();
    } catch (const MyException& e) {
        cout << e.what();
    }
}

Benefits:

  • Provides clear error information
  • Works seamlessly with standard exception handling
  • Encourages structured and maintainable code

5. What is a function template in C++? Write a simple example.

A function template allows a function to operate on generic data types. It provides a way to write one function for multiple types, which is resolved at compile-time.

Syntax:

C++
template <typename T>
T maxVal(T a, T b) {
    return (a > b) ? a : b;
}

6. What is RAII in C++ and how does it relate to exception safety?

RAII (Resource Acquisition Is Initialization) is a design pattern where resources (like memory, file handles, sockets) are acquired in the constructor of an object and released in its destructor. RAII ensures automatic cleanup, even if an exception is thrown, making code exception-safe.

Example:

C++
class FileHandler {
    ifstream file;
public:
    FileHandler(string filename) {
        file.open(filename);
    }
    ~FileHandler() {
        file.close(); // Automatically called
    }
};

In this example, even if an error occurs, the file is properly closed when the object goes out of scope.

7. What is the use of the catch(...) block? How is it different from specific catch blocks?

The catch(...) block is used to catch any type of exception, regardless of its data type or class. It acts as a generic fallback handler.

Example:

C++
try {
    throw 3.14;  // double type
} catch (...) {
    cout << "Caught an unknown exception.";
}

Difference:

  • catch(int e): catches only int exceptions
  • catch(...): catches all exceptions, even if no matching type is found

It’s helpful when you want to ensure that no exception escapes unhandled, but it does not provide specific details about the exception type.

8. What is the difference between inline and constexpr in C++?

Featureinlineconstexpr
PurposeSuggests the compiler to replace functionEnsures compile-time evaluation
Return typeAnyMust return a value known at compile time
C++ VersionAvailable since C++98Introduced in C++11 (improved in C++14/17/20)

Example constexpr:

C++
constexpr int square(int x) {
    return x * x;
}
int arr[square(3)];  // Valid at compile time

Example inline:

C++
inline int cube(int x) {
    return x * x * x;
}

Use constexpr when the value is needed at compile-time, and inline when you want faster execution without function call overhead.

9. Can we catch a derived exception in a base catch block? What are the risks involved?

Yes, C++ allows catching derived exceptions using a base class reference (std::exception &). But object slicing or loss of specific information can occur if exceptions are not caught by reference or pointer.

Example:

C++
#include <iostream>
#include <stdexcept>
using namespace std;

class MyException : public runtime_error {
public:
    MyException(const string& msg) : runtime_error(msg) {}
};

int main() {
    try {
        throw MyException("Custom error occurred");
    } catch (const exception& e) {
        cout << "Caught: " << e.what() << endl;
    }
}

10. What happens if an exception is thrown but not caught?

If an exception is thrown but not caught by any catch block, the program invokes the std::terminate() function, which by default aborts the program.

Example:

C++
void func() {
    throw 10; // no catch block here
}

int main() {
    func(); // Unhandled exception
}

Output:

terminate called after throwing an instance of 'int'
Aborted (core dumped)

This can lead to abrupt termination, loss of data, or unclean resource release. That's why it's critical to ensure every throw has a matching catch, either directly or through stack unwinding.

11. What is stack unwinding in exception handling? Explain its role.

Stack unwinding is the process of cleaning up the function call stack after an exception is thrown and before it is caught. It ensures that destructors of all local objects are called properly in the reverse order of their creation.

Why is it important?

  • Prevents memory/resource leaks
  • Ensures safe destruction of objects
  • Supports RAII (Resource Acquisition Is Initialization)

Example:

C++
#include<iostream>
using namespace std;

class Demo {
public:
    Demo() { cout << "Constructor\n"; }
    ~Demo() { cout << "Destructor\n"; }
};

void test() {
    Demo d;
    throw 1; // Stack unwinding will destroy d
}

int main() {
    try {
        test();
    } catch (...) {
        cout << "Exception caught\n";
    }
}

Output:

Constructor
Destructor
Exception caught

This shows that even when an exception occurs, destructors are called properly to clean up resources.

12. What is the difference between throw; and throw ex; inside a catch block?

  • throw; – Re-throws the current exception (must be used inside a catch block).
  • throw ex; – Throws a copy of the exception ex.

Example:

C++
try {
    throw runtime_error("Error");
} catch (runtime_error& e) {
    cout << "Handling exception...\n";
    throw; // re-throws same exception
}

throw; preserves the original exception type and stack trace, which is important for advanced debugging and exception chaining.

13. What is the use of noexcept in C++ exception handling?

The noexcept keyword is used to indicate that a function will not throw an exception. It helps the compiler with optimizations and improves program clarity.

Example:

C++
void display() noexcept {
    cout << "This function won't throw";
}

Benefits:

  • Faster execution (compiler skips setting up exception-handling code)
  • Clear documentation of function behavior
  • Can cause std::terminate() if the function throws anyway

noexcept is especially important in move constructors and destructors in modern C++.

14. What will happen if you throw an exception from a destructor?

Throwing an exception from a destructor during stack unwinding (i.e., while handling another exception) results in a call to std::terminate(), which aborts the program.

Example:

C++
class Test {
public:
    ~Test() {
        cout << "Destructor called\n";
        throw runtime_error("Error in destructor");
    }
};

int main() {
    try {
        Test t;
        throw logic_error("Main exception");
    } catch (...) {
        cout << "Caught in main\n";
    }
}

Avoid throwing from destructors, especially when exceptions are active. Use std::uncaught_exceptions() (C++17) or try-catch inside destructor to suppress.

15. Can function templates be partially specialized in C++? If not, what is the alternative?

Function templates cannot be partially specialized, only fully specialized. To achieve behavior similar to partial specialization, function overloading or tag dispatching with structs is used.

Example (Alternative using enable_if):

C++
#include <iostream>
#include <type_traits>
using namespace std;

template<typename T>
typename enable_if<is_integral<T>::value>::type
func(T x) {
    cout << "Integral version: " << x << endl;
}

template<typename T>
typename enable_if<is_floating_point<T>::value>::type
func(T x) {
    cout << "Floating point version: " << x << endl;
}

int main() {
    func(10);     // int
    func(3.14);   // double
}

Using std::enable_if, we mimic specialization behavior for functions based on type traits, allowing cleaner and type-specific implementations.

16. What happens when you throw a pointer vs. throw an object in C++?

Throwing a pointer means you're throwing an address. It won’t trigger automatic destruction of the object pointed to, and catching it requires catching the same pointer type. Throwing by value creates a copy, and cleanup is automatic.

Example:

C++
#include <iostream>
using namespace std;

class X {
public:
    X() { cout << "X constructed\n"; }
    ~X() { cout << "X destroyed\n"; }
};

int main() {
    try {
        X* ptr = new X();
        throw ptr;  // throw pointer, not object
    } catch (X* e) {
        cout << "Caught pointer to X\n";
        delete e; // manual cleanup required
    }
}

Throwing objects ensures RAII and automatic cleanup. Throwing pointers must be handled with care to avoid memory leaks.

17. Can a function template throw an exception based on the type it is instantiated with?

Yes. Templates can use static_assert or if constexpr to control logic at compile-time based on type, and can throw exceptions conditionally at runtime.

Example:

C++
#include <iostream>
#include <type_traits>
using namespace std;

template <typename T>
void check(T val) {
    if constexpr (is_same<T, int>::value) {
        if (val < 0) throw runtime_error("Negative int not allowed");
    }
    cout << "Value is: " << val << endl;
}

int main() {
    try {
        check(10);      // OK
        check(-5);      // Throws
    } catch (exception& e) {
        cout << "Caught: " << e.what() << endl;
    }
}

Templates can adapt behavior based on type at compile time. Combining this with runtime exception logic adds powerful type-aware safety mechanisms.


Similar Reads