Giao diện
Memory Management Lab
🎯 Mục tiêu
🎯 Sau bài thực hành này, bạn sẽ:
- Áp dụng RAII pattern để quản lý tài nguyên tự động
- Sử dụng đúng unique_ptr và shared_ptr
- Phát hiện và sửa memory leaks
- Viết custom deleter cho tài nguyên đặc biệt
Mô tả bài tập
Memory management là kỹ năng sống còn trong C++. Bài tập giúp bạn chuyển từ raw pointer sang smart pointer, áp dụng RAII tránh resource leaks.
Yêu cầu
Bài 1: RAII — File Handler
Viết class FileHandler đảm bảo file luôn được đóng khi ra khỏi scope.
cpp
class FileHandler {
std::ofstream file;
public:
explicit FileHandler(const std::string& path); // mở file, throw nếu fail
~FileHandler(); // đóng file tự động
void write(const std::string& content);
FileHandler(const FileHandler&) = delete; // không cho copy
FileHandler& operator=(const FileHandler&) = delete;
};Bài 2: Smart Pointers — Tree Structure
Xây dựng tree: root sở hữu unique_ptr, children dùng shared_ptr.
cpp
struct Node {
std::string value;
std::vector<std::shared_ptr<Node>> children;
explicit Node(const std::string& v) : value(v) {}
~Node() { std::cout << "Destroyed: " << value << std::endl; }
};
std::unique_ptr<Node> buildTree() {
// TODO: Tạo root với 2 children và 1 grandchild
}Bài 3: Custom Deleter
Viết custom deleter cho C-style resources (malloc/free, FILE*/fclose).
cpp
struct MallocDeleter {
void operator()(void* ptr) const { /* TODO */ }
};
using FilePtr = std::unique_ptr<FILE, decltype(&fclose)>;
FilePtr openFile(const char* path, const char* mode) {
// TODO: return FilePtr wrapping fopen
}Gợi ý
Gợi ý Bài 1
Constructor: file.open(path); if (!file.is_open()) throw .... RAII đảm bảo destructor luôn được gọi — kể cả khi exception.
Gợi ý Bài 2
auto root = std::make_unique<Node>("root"); root->children.push_back(std::make_shared<Node>("child"));
Lời giải tham khảo
Xem lời giải
cpp
// Bài 1
FileHandler::FileHandler(const std::string& path) {
file.open(path);
if (!file.is_open()) throw std::runtime_error("Cannot open: " + path);
}
FileHandler::~FileHandler() { if (file.is_open()) file.close(); }
void FileHandler::write(const std::string& content) { file << content; }
// Bài 2
std::unique_ptr<Node> buildTree() {
auto root = std::make_unique<Node>("root");
root->children.push_back(std::make_shared<Node>("child-A"));
root->children.push_back(std::make_shared<Node>("child-B"));
root->children[0]->children.push_back(std::make_shared<Node>("grandchild-1"));
return root;
}
// Bài 3
struct MallocDeleter {
void operator()(void* ptr) const { std::free(ptr); }
};
FilePtr openFile(const char* path, const char* mode) {
return FilePtr(std::fopen(path, mode), fclose);
}