본문으로 건너뛰기 C++ Virtual Destructor — Complete Guide

C++ Virtual Destructor — Complete Guide

C++ Virtual Destructor — Complete Guide

이 글의 핵심

C++ virtual destructor C++, destructor, "memory, Introduction: "Deleted derived class but got memory leak" explained in detail with practical examples.

Introduction: “Deleted Derived Class but Got Memory Leak"

"Deleted with base class pointer but destructor not called”

In C++, when deleting derived class through base class pointer, without virtual destructor, derived class destructor is not called causing memory leak.

// ❌ No virtual destructor
class Base {
public:
    ~Base() {  // Non-virtual destructor
        std::cout << "~Base\n";
    }
};

class Derived : public Base {
    int* data_;
public:
    Derived() : data_(new int[1000]) {}
    
    ~Derived() {
        delete[] data_;  // Not called!
        std::cout << "~Derived\n";
    }
};

int main() {
    Base* ptr = new Derived();
    delete ptr;  // ❌ ~Derived not called → memory leak
    // Output: ~Base
}

What This Guide Covers:

  • Why virtual destructor is needed
  • Memory leak and undefined behavior
  • Pure virtual destructor
  • protected destructor

1. Why Virtual Destructor is Needed

Problem: Non-virtual Destructor

Here is the main implementation:

// ❌ Non-virtual destructor
class Base {
public:
    ~Base() {
        std::cout << "~Base\n";
    }
};

class Derived : public Base {
public:
    ~Derived() {
        std::cout << "~Derived\n";
    }
};

int main() {
    Base* ptr = new Derived();
    delete ptr;  // ❌ Undefined behavior
    // Output: ~Base (derived class destructor not called)
}

Solution: Virtual Destructor

Here is the main implementation:

// ✅ Virtual destructor
class Base {
public:
    virtual ~Base() {
        std::cout << "~Base\n";
    }
};

class Derived : public Base {
public:
    ~Derived() override {
        std::cout << "~Derived\n";
    }
};

int main() {
    Base* ptr = new Derived();
    delete ptr;  // ✅ Correct destructor called
    // Output:
    // ~Derived
    // ~Base
}

2. Memory Leak Examples

Example 1: Dynamic Memory

// ❌ Memory leak
class Base {
public:
    ~Base() {}
};

class Derived : public Base {
    int* data_;
public:
    Derived() : data_(new int[1000000]) {
        std::cout << "Allocated 4MB\n";
    }
    
    ~Derived() {
        delete[] data_;  // Not called!
        std::cout << "Freed 4MB\n";
    }
};

int main() {
    for (int i = 0; i < 100; ++i) {
        Base* ptr = new Derived();
        delete ptr;  // ❌ 4MB leak × 100 = 400MB leak
    }
}

Example 2: File Handle

// ❌ File handle leak
class Base {
public:
    ~Base() {}
};

class FileLogger : public Base {
    std::ofstream file_;
public:
    FileLogger(const std::string& path) : file_(path) {}
    
    ~FileLogger() {
        file_.close();  // Not called!
        std::cout << "File closed\n";
    }
};

int main() {
    Base* ptr = new FileLogger("log.txt");
    delete ptr;  // ❌ File handle leak
}

3. Pure Virtual Destructor

Pure Virtual Destructor

Pure virtual destructor makes class abstract but must provide definition.

// Pure virtual destructor
class Base {
public:
    virtual ~Base() = 0;  // Pure virtual
};

// Definition required
Base::~Base() {
    std::cout << "~Base\n";
}

class Derived : public Base {
public:
    ~Derived() override {
        std::cout << "~Derived\n";
    }
};

int main() {
    // Base b;  // Compile error: abstract class
    Base* ptr = new Derived();
    delete ptr;  // OK
}

When to use: Want to make abstract class without other pure virtual functions.


Summary

Key Points

  1. Virtual destructor: Needed for polymorphic base classes
  2. Memory leak: Occurs without virtual destructor
  3. Pure virtual destructor: Makes class abstract
  4. protected destructor: Prevents deletion through base pointer
  5. Performance: 8-byte vtable pointer overhead

When to Use

Use virtual destructor when:

  • Base class for inheritance
  • Polymorphic usage expected
  • Delete through base pointer

Don’t use when:

  • No inheritance
  • No polymorphism
  • Performance critical (avoid vtable)

Best Practices

  • ✅ Always virtual destructor for polymorphic base
  • ✅ Use override keyword
  • ✅ Consider protected destructor alternative
  • ❌ Don’t forget virtual in base class
  • ❌ Don’t delete derived through non-virtual base

Master virtual destructors for safer C++ inheritance! 🚀


Frequently Asked Questions (FAQ)

Q. When would I use this in practice?

A. Everything about C++ Virtual Destructor : from basic concepts to practical applications.

Q. What should I read before this?

A. Follow the previous article or related articles links at the bottom of each post to learn in sequence. See the C++ series index for the full picture.

Q. Where can I study this more deeply?

A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.


Other articles related to this topic.


Keywords Covered in This Article (Related Search Terms)

This article covers C++, virtual, destructor, inheritance, polymorphism, memory-leak.