Bài học theo mô-đun (2/2)
std::weak_ptr
Mặc dù std::shared_ptr cực kỳ hữu ích nhưng việc chỉ dựa vào quyền sở hữu chung có thể dẫn đến sự cố được gọi là tham chiếu vòng (hoặc phụ thuộc theo chu kỳ).
Nếu hai hoặc nhiều đối tượng đều chứa shared_ptr trỏ đến đối tượng kia thì một vòng lặp khép kín sẽ được tạo. Trong trường hợp này, số lượng tham chiếu của cả hai đối tượng sẽ không bao giờ đạt tới 0, ngăn cản việc giải phóng và gây rò rỉ bộ nhớ.
std::weak_ptr là gì
Để phá vỡ chu kỳ sở hữu, thư viện tiêu chuẩn cung cấp std::weak_ptr. Đây là một con trỏ thông minh quan sát một đối tượng được quản lý bởi shared_ptr nhưng không tăng số lượng tham chiếu.
Nó không trực tiếp sở hữu tài nguyên nên không ngăn chặn được sự phá hủy tài nguyên.
#include <memory>
std::shared_ptr<int> shared = std::make_shared<int>(42);
std::weak_ptr<int> weak = shared; // Does not increment reference count!Xác minh và truy cập tài nguyên
Vì weak_ptr không sở hữu tài nguyên nên tài nguyên có thể bị hủy phân bổ bất kỳ lúc nào (khi tất cả các phiên bản shared_ptr được liên kết nằm ngoài phạm vi).
Để sử dụng tài nguyên được quan sát, chúng ta phải:
- Kiểm tra xem nó có còn hợp lệ hay không bằng cách sử dụng
expired(). - Tạm thời chuyển đổi
weak_ptrthànhshared_ptrbằng phương pháplock(). Nếu tài nguyên vẫn đang hoạt động,lock()sẽ trả vềshared_ptrhợp lệ, nếu không nó sẽ trả về một con trỏ rỗng (nullptr).
if (!weak.expired()) {
// lock() creates a temporary shared_ptr to ensure safe access
if (std::shared_ptr<int> sharedAccess = weak.lock()) {
std::cout << *sharedAccess << std::endl;
}
} else {
std::cout << "Resource deallocated!" << std::endl;
}Hãy tự mình thử
Khai báo một std::weak_ptr<int> có tên wPtr được khởi tạo từ sPtr. Sau đó in kết quả boolean được trả về bởi wPtr.expired() bằng std::cout.
Hiển thị gợi ý
Khai báo `weak_ptr` chỉ ra cùng loại chung `<int>` và gán `sPtr` trực tiếp cho nó.
Giải pháp khả dụng sau 3 lần thử
Sử dụng phương thức lock() trên wPtr để lấy một share_ptr tạm thời. Nếu thao tác thành công (con trỏ không rỗng), hãy in giá trị bị hủy tham chiếu.
Hiển thị gợi ý
Khởi tạo một biến bên trong khối `if` bằng cách gọi `wPtr.lock()`, sau đó in tài nguyên hủy tham chiếu nó bằng dấu hoa thị `*`.
Giải pháp khả dụng sau 3 lần thử