Smart Pointers trong C++ Modern
Tìm hiểu về unique_ptr, shared_ptr, weak_ptr và cách sử dụng smart pointers để quản lý bộ nhớ an toàn trong C++
Smart Pointers trong C++ Modern
Smart pointers là một công cụ mạnh mẽ trong C++ để quản lý bộ nhớ động một cách tự động và an toàn. Từ C++11 trở đi, standard library cung cấp ba loại smart pointers chính: unique_ptr, shared_ptr, và weak_ptr.
Tại sao cần Smart Pointers?
Với raw pointers truyền thống, chúng ta phải tự quản lý việc new và delete:
// Cách cũ - dễ gây memory leak
MyClass* obj = new MyClass();
// ... sử dụng obj ...
delete obj; // Dễ quên!Vấn đề xảy ra khi:
- Quên
delete→ memory leak deletenhiều lần → undefined behavior- Exception xảy ra trước khi
delete→ memory leak
Smart pointers giải quyết các vấn đề này!
unique_ptr - Sole Ownership
unique_ptr đại diện cho exclusive ownership - chỉ một smart pointer được sở hữu object tại một thời điểm.
#include <memory>
#include <iostream>
class MyClass {
public:
MyClass() { std::cout << "Constructor\n"; }
~MyClass() { std::cout << "Destructor\n"; }
void doSomething() { std::cout << "Doing something\n"; }
};
void example_unique_ptr() {
// Tạo unique_ptr
std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>();
// Sử dụng như pointer thông thường
ptr1->doSomething();
// Di chuyển ownership
std::unique_ptr<MyClass> ptr2 = std::move(ptr1);
// ptr1 giờ là nullptr
// Tự động delete khi ra khỏi scope
// Không cần gọi delete!
}Đặc điểm của unique_ptr
- Zero overhead: Không tốn thêm bộ nhớ so với raw pointer
- Move-only: Không thể copy, chỉ có thể move
- Automatic cleanup: Tự động delete khi ra khỏi scope
shared_ptr - Shared Ownership
shared_ptr cho phép nhiều owners cùng sở hữu một object. Object chỉ bị delete khi tất cả shared_ptr đều ra khỏi scope.
#include <memory>
#include <vector>
void example_shared_ptr() {
// Tạo shared_ptr
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
std::cout << "Reference count: " << ptr1.use_count() << "\n"; // 1
{
// Copy - tăng reference count
std::shared_ptr<MyClass> ptr2 = ptr1;
std::cout << "Reference count: " << ptr1.use_count() << "\n"; // 2
std::shared_ptr<MyClass> ptr3 = ptr1;
std::cout << "Reference count: " << ptr1.use_count() << "\n"; // 3
}
// ptr2 và ptr3 ra khỏi scope
std::cout << "Reference count: " << ptr1.use_count() << "\n"; // 1
// Object sẽ bị delete khi ptr1 ra khỏi scope
}Use Cases cho shared_ptr
- Nhiều components cần truy cập cùng một object
- Container của smart pointers
- Callback functions giữ reference đến object
- Graph structures với nhiều connections
weak_ptr - Breaking Circular References
weak_ptr là "weak reference" đến object được quản lý bởi shared_ptr, không làm tăng reference count.
#include <memory>
class Node {
public:
std::shared_ptr<Node> next;
std::weak_ptr<Node> prev; // Dùng weak_ptr để tránh circular reference
int data;
Node(int val) : data(val) {}
~Node() { std::cout << "Node " << data << " destroyed\n"; }
};
void example_weak_ptr() {
auto node1 = std::make_shared<Node>(1);
auto node2 = std::make_shared<Node>(2);
node1->next = node2;
node2->prev = node1; // weak_ptr không tạo cycle
// Sử dụng weak_ptr
if (auto prev = node2->prev.lock()) { // lock() trả về shared_ptr
std::cout << "Previous node: " << prev->data << "\n";
}
// Tự động cleanup, không có memory leak
}Best Practices
1. Ưu tiên make_unique và make_shared
// Good
auto ptr = std::make_unique<MyClass>();
auto shared = std::make_shared<MyClass>();
// Avoid
std::unique_ptr<MyClass> ptr(new MyClass()); // Rủi ro exception2. Truyền smart pointers đúng cách
// Nếu function không giữ ownership
void process(const MyClass& obj); // Best - pass by reference
void process(MyClass* obj); // OK - raw pointer
// Nếu function giữ shared ownership
void store(std::shared_ptr<MyClass> ptr); // Pass by value
// Nếu function take ownership
void take(std::unique_ptr<MyClass> ptr); // Pass by value3. Sử dụng đúng loại smart pointer
| Use Case | Smart Pointer |
|---|---|
| Exclusive ownership | unique_ptr |
| Shared ownership | shared_ptr |
| Temporary reference | weak_ptr |
| Factory functions | unique_ptr (return value) |
Performance Considerations
// unique_ptr: No overhead
sizeof(std::unique_ptr<int>) == sizeof(int*) // true
// shared_ptr: Extra overhead cho reference counting
sizeof(std::shared_ptr<int>) == 2 * sizeof(int*) // trueunique_ptr: Không có overheadshared_ptr: Reference counting có overhead nhỏweak_ptr: Tương tựshared_ptr
Kết luận
Smart pointers là công cụ essential trong Modern C++. Chúng giúp:
- Tránh memory leaks
- Exception-safe
- Express ownership semantics rõ ràng
- Không có performance overhead (unique_ptr)
Rule of thumb: Luôn sử dụng smart pointers thay vì raw pointers khi quản lý ownership!
Bài viết liên quan
Tối ưu hiệu suất với Compiler Optimization
Compiler optimization có thể cải thiện hiệu suất code lên đến 300%. Tìm hiểu các optimization levels và khi nào nên sử dụng chúng.
Git là gì? Các lệnh thường dùng khi đi làm, Github & Gitlab, Source Control trong VSCode, Git Graph, Git Blame, Sourcetree
Tìm hiểu Git từ cơ bản đến nâng cao: các lệnh Git thiết yếu khi đi làm, làm việc với Github/Gitlab, và sử dụng các công cụ Git GUI như VSCode Source Control, Git Graph, Git Blame và Sourcetree.
Neural Networks từ Zero: Backpropagation
Backpropagation là trái tim của deep learning. Hiểu rõ thuật toán này giúp bạn master được cách neural networks học từ data.