+3

[C++ OOP Thực Chiến] Bài 17: Destructor - "Người dọn rác" tận tụy và bài học xương máu về Memory Leak

Chào anh em! Ở các bài trước, chúng ta đã dùng new để xin cấp phát bộ nhớ rất nhiều. Nhưng hãy nhớ một quy tắc sắt đá trong C++: Có vay thì phải có trả. Nếu Constructor là nơi chúng ta "mượn" tài nguyên (RAM, File, Connection) từ hệ điều hành, thì Destructor (Hàm phá hủy) chính là nơi chúng ta trả lại những thứ đó trước khi Object biến mất hoàn toàn khỏi RAM.

1. Destructor là gì?

Destructor là một phương thức đặc biệt, tự động được gọi ngay trước khi một Object bị hủy.

  • Cú pháp: Tên hàm bắt đầu bằng dấu ngã ~ theo sau là tên Class (ví dụ: ~SmartBuffer()).
  • Đặc điểm: Không có tham số, không có kiểu trả về, và chỉ có duy nhất một Destructor trong mỗi Class.

2. RAII - Tư duy "Sống sạch" của Backend Engineer

Trong giới C++ chuyên nghiệp, có một triết lý gọi là RAII (Resource Acquisition Is Initialization). Hiểu nôm na là: Gắn chặt vòng đời của tài nguyên vào vòng đời của Object.

  1. Khởi tạo Object -> Chiếm giữ tài nguyên (Mở file, connect DB, cấp phát RAM).
  2. Object hết vòng đời -> Destructor tự chạy -> Giải phóng tài nguyên ngay lập tức.

Điều này giúp bạn cực kỳ an tâm. Dù code của bạn có bị lỗi nửa chừng hay thoát hàm đột ngột, C++ vẫn đảm bảo Destructor được gọi để dọn dẹp "bãi chiến trường".

3. Code Demo: Quản lý kết nối Database giả lập

Hãy xem cách một Destructor bảo vệ hệ thống khỏi việc "treo" kết nối:

#include <iostream>
#include <string>

using namespace std;

class DatabaseConnection {
private:
    string dbName;
    string* connectionStatus; // Giả lập tài nguyên động

public:
    // Constructor: Mở kết nối
    DatabaseConnection(string name) : dbName(name) {
        connectionStatus = new string("CONNECTED");
        cout << "[INIT] Da mo ket noi den DB: " << dbName << "\n";
    }

    void query(string sql) {
        cout << "[QUERY] Dang thuc thi: " << sql << " tren " << dbName << "...\n";
    }

    // DESTRUCTOR: Đóng kết nối và giải phóng RAM
    ~DatabaseConnection() {
        cout << "[CLEANUP] Dang chuan bi dong ket noi " << dbName << "...\n";
        
        // Giai phong vung nho dong
        if (connectionStatus != nullptr) {
            delete connectionStatus;
            connectionStatus = nullptr;
        }
        
        cout << "[CLEANUP] Ket noi da dong. RAM da sach!\n";
    }
};

void testStack() {
    cout << "\n--- Bat dau ham testStack ---\n";
    DatabaseConnection localDb("MySQL_Local");
    localDb.query("SELECT * FROM users");
    // Het ham testStack, localDb la bien Stack se TU DONG bi huy
    cout << "--- Ket thuc ham testStack ---\n";
}

int main() {
    // 1. Kiem tra bien Stack
    testStack();

    cout << "\n-----------------------------\n";

    // 2. Kiem tra bien Heap
    cout << "\n--- Khoi tao bien Heap ---\n";
    DatabaseConnection* remoteDb = new DatabaseConnection("PostgreSQL_Remote");
    remoteDb->query("UPDATE orders SET status='PAID'");
    
    // Luu y: Neu khong co dong duoi day, Destructor se KHONG BAO GIO duoc goi
    delete remoteDb; 

    return 0;
}

Bài học rút ra: * Với biến Stack: C++ tự lo cho bạn.

  • Với biến Heap (new): Bạn phải tự dùng delete. Nếu quên delete, Destructor không chạy, tài nguyên bị rò rỉ (Leak).

Tạm kết & Gợi mở

Destructor là chốt chặn cuối cùng giúp mã nguồn của bạn trở nên chuyên nghiệp và tin cậy. Hiểu về nó là bạn đã nắm được 90% kỹ năng quản lý bộ nhớ trong C++.

Tuy nhiên, từ đầu series đến giờ, chúng ta luôn thao tác trên dữ liệu riêng của từng Object (mỗi ví có số dư riêng, mỗi nhân vật có máu riêng). Nhưng trong thực tế, đôi khi chúng cả cần một thứ gì đó "dùng chung" cho tất cả mọi người.

Ví dụ: Bạn muốn đếm xem có tổng cộng bao nhiêu kết nối Database đang mở trên toàn server? Chẳng lẽ mỗi Object lại giữ một biến đếm riêng?

Đó là lúc chúng ta cần đến những thành viên "vượt lên trên thực thể". Hẹn gặp lại bố đời ở Bài 18: Thành viên tĩnh (Static Data Member) - Bí mật về những biến số "vượt thời gian". Nhớ Upvote để ủng hộ mình nhé!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí