C++ Exception Handling & Templates Interview Questions (original) (raw)

Last Updated : 26 Aug, 2025

In modern C++, developers aim to write programs that do not easily break, can be reused in different situations, and run efficiently. Two important features that help achieve this are:

1. What is the difference between throw, try, and catch in C++?

In C++, exceptions are handled using three keywords:

Example:

C++ `

#include using namespace std;

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

`

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

Example:

C++ `

template 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 and 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:

Example:

C++ `

#include

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 #include 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:

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 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:

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++?

inline constexpr
Suggests to the compiler to expand code at call site Indicates that the value/function can be evaluated at compile time
Used for small functions to reduce function call overhead Used for constant expressions and compile-time evaluation
No guarantee of compile-time evaluation Must be evaluated at compile time (if possible)
Can return any type, computed at runtime or compile-time Must return a constant value, known at compile time
C++98 C++11
Performance optimization Defining compile-time constants and expressions
Can contain any valid code Limited to constant expressions and no side effects
inline constexpr
Suggests the compiler to replace function Ensures compile-time evaluation
Any Must return a value known at compile time
Available since C++98 Introduced in C++11 (improved in C++14/17/20)

E**xample 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 #include 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 anywhere in the call stack, the program calls std::terminate(), which by default aborts execution. Exceptions can propagate up the call stack until a suitable catch block is found. If none is found, the program terminates.

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 call stack after an exception is thrown and before it is caught. During unwinding, destructors of all local objects are called in reverse order of construction, ensuring proper cleanup. This prevents resource leaks and enforces RAII (Resource Acquisition Is Initialization).

Why is it important?

Example:

C++ `

#include 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?

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 specifies that a function does not throw exceptions. It makes intent clear to both the compiler and developers. If a noexcept function does throw, std::terminate() is called. noexcept is especially important for move constructors and destructors, where it enables optimizations such as exception-safe move operations in standard containers.

Example:

C++ `

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

`

Benefits:

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. Partial specialization is only supported for class templates. To achieve similar behavior with functions, you can use overloading, SFINAE (Substitution Failure Is Not An Error), or tools like std::enable_if and if constexpr to tailor behavior for specific categories of types.

Example (Alternative using enable_if):

C++ `

#include #include using namespace std;

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

template typename enable_if<is_floating_point::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 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 #include using namespace std;

template 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.