Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C++

Destructors ใน C++ (ทำลายออบเจกต์)

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 5C++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 ทำให้เอง
};