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
- Virtual destructor: Needed for polymorphic base classes
- Memory leak: Occurs without virtual destructor
- Pure virtual destructor: Makes class abstract
- protected destructor: Prevents deletion through base pointer
- 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
Related Articles
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++ Rule of Five | ‘특수 멤버 함수’ 가이드
- C++ 상속과 다형성 | ‘virtual 함수’ 완벽 가이드
- C++ 슬라이싱 문제 | ‘객체가 잘렸어요’ 상속 복사 에러 해결
이 글에서 다루는 키워드 (관련 검색어)
C++, virtual, destructor, inheritance, polymorphism, memory-leak 등으로 검색하시면 이 글이 도움이 됩니다.