Menu
CoddyTech

Bộ nhớ động (new/delete)

Thuộc phần Lập trình hướng đối tượng trong hành trình C++ của Coddy. Bài học 14 trên 104.

Bây giờ bạn đã hiểu con trỏ và tham chiếu, hãy vận dụng chúng với cấp phát bộ nhớ động. Các toán tử new và delete cho phép bạn tạo và hủy đối tượng trên heap khi chương trình chạy.

Dùng new để cấp phát bộ nhớ và nhận về con trỏ trỏ đến vùng nhớ đó:

int* num = new int;        // Cấp phát một số nguyên (integer)
*num = 42;                 // Gán giá trị (value) thông qua con trỏ (pointer)

Player* player = new Player("Hero");  // Cấp phát đối tượng (object)

Mỗi new phải có một delete tương ứng để giải phóng bộ nhớ:

delete num;      // Giải phóng một đối tượng
delete player;   // Gọi hàm hủy, rồi giải phóng bộ nhớ

Với mảng, hãy dùng new[] và delete[]:

int* scores = new int[5];    // Cấp phát mảng (array) gồm 5 số nguyên (integer)
scores[0] = 100;

delete[] scores;             // Giải phóng mảng, chú ý cặp ngoặc vuông!

Các lỗi thường gặp cần tránh:

// Rò rỉ bộ nhớ: quên dùng delete
int* ptr = new int(10);
ptr = new int(20);    // Không còn truy cập được vùng nhớ cấp phát đầu tiên!

// Con trỏ treo: sử dụng sau khi gọi delete
delete ptr;
*ptr = 5;             // Hành vi không xác định!

// Dùng sai lệnh delete
int* arr = new int[10];
delete arr;           // Sai! Phải dùng delete[]

Sau khi xóa, hãy đặt các con trỏ thành nullptr để tránh vô tình dùng lại. Quản lý bộ nhớ thủ công dễ gây lỗi, vì vậy C++ hiện đại ưu tiên dùng con trỏ thông minh, mình sẽ tìm hiểu về chúng ở phần tiếp theo.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống lưu trữ tin nhắn đơn giản để minh họa cách cấp phát bộ nhớ động (dynamic memory allocation) bằng new và delete.

Bạn sẽ tạo hai tệp để sắp xếp code:

  • MessageBox.h: Định nghĩa lớp MessageBox để quản lý một mảng tin nhắn được cấp phát động. Lớp này cần có:
    • Một con trỏ riêng tư trỏ đến mảng chuỗi được cấp phát động
    • Một số nguyên riêng tư theo dõi số lượng tin nhắn hiện tại
    • Một số nguyên riêng tư lưu sức chứa tối đa
    • Một hàm khởi tạo nhận sức chứa và cấp phát mảng bằng new[]
    • Một hàm hủy giải phóng bộ nhớ đúng cách bằng delete[] và in ra "MessageBox destroyed"
    • Một phương thức addMessage(string msg) thêm tin nhắn nếu còn chỗ, trả về true nếu thành công hoặc false nếu đã đầy
    • Một phương thức printAll() in từng tin nhắn đã lưu trên một dòng riêng
  • main.cpp: Đọc một giá trị sức chứa và số lượng tin nhắn từ đầu vào. Sau đó đọc từng chuỗi tin nhắn tương ứng. Tạo một MessageBox trên heap bằng new, thêm tất cả tin nhắn vào đó, gọi printAll(), rồi xóa MessageBox đúng cách để giải phóng bộ nhớ.

Định dạng đầu vào:

  • Dòng đầu tiên: sức chứa (số nguyên)
  • Dòng thứ hai: số lượng tin nhắn cần thêm (số nguyên)
  • Các dòng tiếp theo: mỗi dòng chứa một tin nhắn

Hãy nhớ: mỗi new cần có một delete tương ứng, và mỗi new[] cần có một delete[] tương ứng. Sau khi xóa, bạn nên đặt con trỏ thành nullptr.

Thêm tệp tiêu đề vào main.cpp bằng #include "MessageBox.h".

Tự làm thử

#include <iostream>
#include <string>
#include "MessageBox.h"
using namespace std;

int main() {
    int capacity;
    int numMessages;
    
    // Đọc dung lượng và số lượng tin nhắn
    cin >> capacity;
    cin >> numMessages;
    cin.ignore(); // Xóa ký tự xuống dòng sau số
    
    // TODO: Tạo MessageBox trên vùng nhớ heap bằng new
    
    // TODO: Đọc và thêm tất cả tin nhắn vào MessageBox
    for (int i = 0; i < numMessages; i++) {
        string message;
        getline(cin, message);
        // Thêm tin nhắn vào MessageBox
    }
    
    // TODO: Gọi printAll() để hiển thị tất cả tin nhắn
    
    // TODO: Xóa MessageBox để giải phóng bộ nhớ
    // Nhớ gán con trỏ thành nullptr sau khi xóa
    
    return 0;
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch C++ online