ReviseAlgo Logo

Object-Oriented Programming

Destructors

Automatic cleanup when objects go out of scope or are deleted

Interview: Core C++ memory management — virtual destructor rule, noexcept, and RAII

Destructors

A destructor is a special member function called automatically when an object is destroyed — when it goes out of scope, when delete is called on a heap object, or during exception stack unwinding. The destructor's job is to release any resources the object owns. With proper RAII design, destructors eliminate the need for manual cleanup.

The Virtual Destructor Rule

If a class is intended to be used as a base class and objects will be deleted through base class pointers, the destructor must be virtual. Without virtual ~Base(), deleting a derived object via a base pointer calls only the base destructor — the derived destructor never runs, leaking any resources the derived class owns.

Destructor Properties

  • Takes no parameters, returns nothing, cannot be overloaded — one destructor per class.
  • Automatically called by the compiler — you never call destructors explicitly except in rare placement-new scenarios.
  • Destructor order: derived destructor first, then base destructor (reverse of construction).
  • Should be noexcept — exceptions during stack unwinding cause std::terminate.

= default and = delete

Use = default to explicitly request the compiler-generated destructor. Use = delete to prevent destruction (rare — makes the type non-destroyable). Declaring a destructor virtual but defaulting it (virtual ~Base() = default;) is the standard pattern for base classes that don't need custom cleanup.

Interview Corner

Q: When is it undefined behavior to delete through a base class pointer?

A: When the base class destructor is not virtual. The compiler uses static dispatch — only the base destructor is called. The derived object is not fully destroyed, causing resource leaks and potentially corrupt heap state. The fix: always declare destructors virtual in polymorphic base classes. If the class should not be used polymorphically, mark it final.

Q: What happens if a destructor throws an exception?

A: If a destructor throws during normal execution, the exception propagates (but this is poor design). If a destructor throws while another exception is already propagating (stack unwinding), std::terminate is called immediately — the program crashes. This is why destructors must be noexcept. Catch any internal exceptions inside the destructor and handle them there.

Common Pitfalls

  • Non-virtual destructor in polymorphic base: Deleting through a base pointer with a non-virtual destructor is undefined behavior. Always use virtual ~Base() for bases.
  • Throwing from destructor: Can cause std::terminate during stack unwinding. Always mark destructors noexcept and absorb exceptions internally.

Best Practices

  • Every polymorphic base class should have virtual ~Base() = default;
  • Always mark destructors noexcept (they are implicitly noexcept in C++11 unless you declare otherwise).
  • Follow the Rule of Zero — if your class uses RAII members, the default destructor handles cleanup correctly.