본문으로 건너뛰기
Previous
Next
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

Here is detailed implementation code using C++. Define a class to encapsulate data and functionality, process data with loops. Understand the role of each part while examining the code.

// ❌ 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

Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.

// ❌ 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.

Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.

// 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! 🚀


자주 묻는 질문 (FAQ)

Q. 이 내용을 실무에서 언제 쓰나요?

A. Everything about C++ Virtual Destructor : from basic concepts to practical applications. Master key content quickly with… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.

Q. 선행으로 읽으면 좋은 글은?

A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.

Q. 더 깊이 공부하려면?

A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.


같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.


이 글에서 다루는 키워드 (관련 검색어)

C++, virtual, destructor, inheritance, polymorphism, memory-leak 등으로 검색하시면 이 글이 도움이 됩니다.