ProgrammingC++ Backend Developer

Explain the difference between stack unwinding and resource management in exception handling in C++. How to ensure proper resource release?

Pass interviews with Hintsage AI assistant

Answer.

Background:

C++ was originally designed with a focus on performance, and therefore resource management (memory, files, streams, sockets) often occurs manually. When an exception occurs, it's necessary to clean up acquired resources. Stack unwinding is a mechanism used in C++ to properly terminate function execution during an exception throw.

Problem:

When an exception is thrown, control immediately transfers to catch blocks, and intermediate functions are "unwound": their destructors are called, but explicit calls to freeing functions may be missed (for example, if objects that automatically manage resources are not used).

Solution:

In C++, resource release should be entrusted to destructors rather than calling freeing functions manually. The RAII (Resource Acquisition Is Initialization) pattern is a clear way to make resource release automatic. During stack unwinding, the destructor will be called, and the resource will be released regardless of the exit path from the function.

Code Example:

#include <fstream> #include <stdexcept> void readFile(const std::string& filename) { std::ifstream file(filename); // Will open and close correctly even on exception if (!file.is_open()) { throw std::runtime_error("File cannot be opened"); } // ... read file } // file will close even on exception

Key Features:

  • Stack unwinding is the standard mechanism for destructing objects when an exception is thrown.
  • Always perform resource release in destructors.
  • Use RAII or standard classes (e.g., smart pointers).

Trick Questions.

If there is delete ptr; in the catch block, is that enough to clean up memory?

No, if an exception occurs between memory allocation and the catch block, the memory may not be cleaned up. It's better to use std::unique_ptr or put delete in the destructor.

Code Example:

void foo() { int* data = new int[10]; // ... throw std::runtime_error("fail"); delete[] data; // won't be called on exception }

Can stack unwinding skip calling the destructor for an object allocated on the stack?

No, all local objects (not destructed before the exception throw point) will be destroyed in the reverse order of their creation, destructors will be called reliably.

Can I use goto or longjmp to exit from the try block and expect destructors to be called?

No. C++ guarantees destructor calls only during stack unwinding due to an exception, not due to incorrect flow control (goto, setjmp/longjmp).

Common Mistakes and Anti-Patterns

  • Manually cleaning up resources inside try-catch, ignoring destructors
  • Using raw pointers instead of RAII or standard classes
  • Abstracting exception handling in a way that resources are not released (e.g., setjmp/longjmp)

Real-life Example

Negative Case

A programmer allocates memory using new, handles exceptions by freeing memory in the catch block, but forgets about other exit paths from the function.

Pros:

  • Initially seems simple and "transparent"

Cons:

  • If an exception is thrown somewhere unexpected, it results in memory leakage
  • Difficult to test and maintain

Positive Case

std::unique_ptr and RAII classes are used for all resources, and release does not depend on try/catch.

Pros:

  • No resource leaks
  • Error handling logic becomes simpler

Cons:

  • Requires a better understanding of the standard library and language idioms