Chuyển đến nội dung chính
Mô-đun 7 · Bài học 2 trong tổng số 216/18 trong khóa học~12 min
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.

C++
#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:

  1. Kiểm tra xem nó có còn hợp lệ hay không bằng cách sử dụng expired().
  2. Tạm thời chuyển đổi weak_ptr thành shared_ptr bằng phương pháp lock(). Nếu tài nguyên vẫn đang hoạt động, lock() sẽ trả về shared_ptr hợp lệ, nếu không nó sẽ trả về một con trỏ rỗng (nullptr).
C++
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ử

tập thể dục#cpp.m7.l2.e1
Nỗ lực: 0Đang tải…

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.

Đang tải trình chỉnh sửa…
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ử

tập thể dục#cpp.m7.l2.e2
Nỗ lực: 0Đang tải…

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.

Đang tải trình chỉnh sửa…
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ử