Đó là để cho phép quản lý lâu dài.
Khối điều khiển không bị hủy cho đến khi weak_count
bằng không. Đối tượng storage
bị hủy ngay sau khi count
đạt đến 0. Điều đó có nghĩa là bạn cần gọi trực tiếp trình phá hủy của storage
khi số đếm đạt đến 0 và không phải trong trình phá hủy của khối điều khiển.
Để ngăn chặn destructor của khối điều khiển gọi destructor của storage
, loại thực tế của storage
không được là T
.
Nếu chúng tôi chỉ có số lượng tham chiếu mạnh, thì T
sẽ ổn (và đơn giản hơn nhiều).
Thực tế, việc triển khai phức tạp hơn một chút so với điều này. Hãy nhớ rằng shared_ptr có thể được xây dựng bằng cách phân bổ T
với new
và sau đó xây dựng shared_ptr
từ đó. Do đó, kiểm soát khối thực tế trông giống như:
template<typename T>
struct shared_ptr_control_block {
std::atomic<long> count;
std::atomic<long> weak_count;
T* ptr;
};
và những gì make_shared
giao đất là:
template<typename T>
struct both {
shared_ptr_control_block cb;
std::aligned_storage_t<sizeof (T), alignof (T)> storage;
};
Và cb.p
được thiết lập đến địa chỉ của storage
. Phân bổ cấu trúc both
trong make_shared
có nghĩa là chúng tôi nhận được một phân bổ bộ nhớ duy nhất, thay vì hai (và phân bổ bộ nhớ là tốn kém).
Lưu ý: Tôi đã đơn giản hóa: Phải có cách để destructor shared_ptr biết khối kiểm soát có phải là một phần của both
(trong trường hợp đó bộ nhớ không thể được giải phóng cho đến khi thực hiện) hay không (trong trường hợp đó có thể được giải phóng sớm hơn). Đây có thể là một cờ bool đơn giản (trong trường hợp khối điều khiển lớn hơn), hoặc bằng cách sử dụng một số bit dự phòng trong một con trỏ (không phải là di động - nhưng việc triển khai thư viện chuẩn không cần phải di chuyển). Việc triển khai có thể thậm chí là nhiều hơn phức tạp để tránh lưu trữ con trỏ tại tất cả trong trường hợp make_shared
.
Nguồn
2017-01-18 09:53:50
Ah, tôi thấy bây giờ. Vì vậy, nếu chúng ta chỉ có một số tham chiếu (số đếm mạnh), thì một 'T' sẽ là đủ, đúng không? –
@ZizhengTai, có –
Có thể đáng nói đến là make_shared kết hợp khối điều khiển và đối tượng để giảm số lượng phân bổ bộ nhớ cần thiết. chỉ đơn giản là xây dựng một shared_ptr yêu cầu một phân bổ cho đối tượng đang được chia sẻ và một phân bổ cho khối điều khiển. –