Destructor เป็นฟังก์ชันพิเศษที่ทำงานอัตโนมัติเมื่อ Object สิ้นสุดอายุ (Out of scope, delete, จบโปรแกรม)
ลักษณะสำคัญ
- ชื่อเหมือนคลาส แต่ขึ้นต้นด้วย ~ (tilde)
- ไม่มีพารามิเตอร์ และ ไม่มีคืนค่า
- แต่ละคลาสมีได้ เพียง 1 ตัว (ไม่ overload ได้)
- ทำงาน อัตโนมัติ - ไม่เรียกเอง (ยกเว้น placement new)
โค้ดตัวอย่าง
#include <iostream>
using namespace std;
class Demo {
private:
int num1, num2;
public:
// Parameterized Constructor
Demo(int n1, int n2) {
cout << "Inside Constructor" << endl;
num1 = n1;
num2 = n2;
}
void display() {
cout << "num1 = " << num1 << endl;
cout << "num2 = " << num2 << endl;
}
// Destructor
~Demo() {
cout << "Inside Destructor" << endl;
}
};
int main() {
Demo obj1(10, 20); // Constructor เรียก
obj1.display();
// จบ main → obj1 ออก scope → Destructor เรียกอัตโนมัติ
return 0;
}
ผลลัพธ์
Inside Constructor num1 = 10 num2 = 20 Inside Destructor
ลำดับการเรียก Constructor/Destructor
{
Demo a(1); // Constructor a
{
Demo b(2); // Constructor b
} // Destructor b (บล็อกในสุดจบก่อน)
Demo c(3); // Constructor c
} // Destructor c, แล้ว Destructor a (LIFO)
ผลลัพธ์ลำดับ
Inside Constructor (a=1) Inside Constructor (b=2) Inside Destructor (b=2) Inside Constructor (c=3) Inside Destructor (c=3) Inside Destructor (a=1)
การใช้งานจริง: จัดการ Resource (RAII)
#include <iostream>
#include <fstream>
#include <memory>
using namespace std;
class FileHandler {
fstream file;
string filename;
public:
FileHandler(const string& fname, ios::openmode mode = ios::in | ios::out)
: filename(fname) {
file.open(fname, mode);
if (!file.is_open())
throw runtime_error("Cannot open file: " + fname);
cout << "Opened: " << fname << endl;
}
~FileHandler() {
if (file.is_open()) {
file.close();
cout << "Closed: " << filename << endl;
}
}
// Disable copy (Rule of 5)
FileHandler(const FileHandler&) = delete;
FileHandler& operator=(const FileHandler&) = delete;
// Allow move
FileHandler(FileHandler&& other) noexcept
: file(std::move(other.file)), filename(std::move(other.filename)) {}
void write(const string& data) {
if (file.is_open()) file << data;
}
};
int main() {
try {
FileHandler f("test.txt");
f.write("Hello RAII!");
} catch (const exception& e) {
cout << "Error: " << e.what() << endl;
}
// File ปิดอัตโนมัติแม้จะมี Exception
return 0;
}
Virtual Destructor (สำคัญมากสำหรับ Polymorphism)
class Base {
public:
virtual ~Base() { cout << "Base Destructor" << endl; }
};
class Derived : public Base {
int* data;
public:
Derived() { data = new int[100]; }
~Derived() {
delete[] data;
cout << "Derived Destructor" << endl;
}
};
int main() {
Base* ptr = new Derived();
delete ptr; // เรียก ~Derived() แล้ว ~Base() ✓
// ถ้า Base ไม่มี virtual destructor:
// delete ptr → เรียก ~Base() เท่านั้น → Memory Leak!
return 0;
}
Rule of 3 / 5 / 0
| Rule | เมื่อไหร่ต้องเขียน | ฟังก์ชันที่ต้องเขียน |
|---|---|---|
| Rule of 3 | จัดการ Resource เอง (raw pointer, file, socket) | Destructor, Copy Constructor, Copy Assignment |
| Rule of 5 | C++11+ รองรับ Move | + Move Constructor, Move Assignment |
| Rule of 0 | ใช้ RAII types (vector, string, unique_ptr, shared_ptr) | ไม่ต้องเขียนอะไรเลย (Compiler ทำให้) |
Modern C++: ใช้ Smart Pointers แทน
#include <memory>
class Modern {
unique_ptr<int[]> data; // Auto delete[]
public:
Modern(int size) : data(make_unique<int[]>(size)) {}
// ไม่ต้องเขียน Destructor! unique_ptr ทำให้เอง
};