Hàm hủy trong C++

Hàm hủy (Destructor) là một hàm đặc biệt được gọi tự động khi đối tượng bị xóa khỏi bộ nhớ. Nó đóng vai trò như lời cuối cùng của một đối tượng trước khi biến mất, giúp giải phóng các tài nguyên mà đối tượng đã chiếm dụng — chẳng hạn như bộ nhớ động, file mở, hoặc kết nối mạng.

Đặc điểm chính:

  • Không có tham số và không trả về giá trị.
  • Tên hàm bắt đầu bằng dấu ~, theo sau là tên lớp.
  • Chỉ có thể khai báo một lần duy nhất cho mỗi lớp (không thể ghi đè).
  • Nếu không tự định nghĩa, trình biên dịch sẽ tạo ra một hàm hủy mặc định.

Cú pháp khai báo:

~TênLớp();

Ví dụ minh họa:

class Student {
public:
    Student() {
        std::cout << "Student được khởi tạo\n";
    }
    
    ~Student() {
        std::cout << "Student đang bị hủy\n";
    }

private:
    std::string name;
};

Khi nào cần định nghĩa hàm hủy?

Khi đối tượng sử dụng các tài nguyên bên ngoài vùng nhớ cục bộ như:

  • Bộ nhớ được cấp phát động (new).
  • File hoặc luồng I/O đang mở.
  • Các tham chiếu đến tài nguyên hệ thống.

Nếu không giải phóng đúng lúc, có thể dẫn đến rò rỉ tài nguyên.

Ví dụ:

class DataHandler {
public:
    DataHandler() {
        data = new int[100];
    }

    ~DataHandler() {
        delete[] data;  // Giải phóng bộ nhớ trước khi hủy
        std::cout << "Bộ nhớ đã được giải phóng\n";
    }

private:
    int* data;
};

Ví dụ thực tế: Kiểm tra việc gọi hàm hủy

#include <iostream>
#include <string>

class Teacher {
public:
    Teacher(const std::string& n = "Unknown", int a = 30)
        : name(n), age(a) {
        std::cout << "Teacher(" << name << ", " << age << ") được tạo\n";
    }

    Teacher(const Teacher& other)
        : name(other.name), age(other.age) {
        std::cout << "Sao chép Teacher: " << name << "\n";
    }

    ~Teacher() {
        std::cout << "Teacher " << name << " bị hủy\n";
    }

    void setName(const std::string& n) { name = n; }
    std::string getName() const { return name; }
    void setAge(int a) { age = a; }
    int getAge() const { return age; }

private:
    std::string name;
    int age;
};

int main() {
    Teacher t1;                    // Tạo từ stack
    Teacher* t2 = new Teacher();   // Tạo từ heap
    delete t2;                     // Hủy đối tượng trên heap

    Teacher t3(t1);                // Sao chép đối tượng

    std::cout << "Chương trình kết thúc\n";
    return 0;
}

Kết quả in ra:

Teacher(Unknown, 30) được tạo
Teacher(Unknown, 30) được tạo
Sao chép Teacher: Unknown
Chương trình kết thúc
Teacher Unknown bị hủy
Teacher Unknown bị hủy
Teacher Unknown bị hủy

Nhận xét: Mỗi khi đối tượng bị loại bỏ — dù là từ stack hay heap — hàm hủy đều được gọi tự động. Việc sao chép cũng không làm ảnh hưởng đến việc hủy.

Thẻ: C++ destructor memory management RAII stack allocation

Đăng vào ngày 4 tháng 9 lúc 07:18