Có một số câu hỏi hôm nay về std::weak_ptr
và std::owner_less
và cách sử dụng chúng trong các vùng chứa liên kết std::set
và std::map
. Có một số bài viết nói rằng sử dụng weak_ptr
trong một std::set
là không chính xác, vì nếu con trỏ yếu hết hạn, nó sẽ là Hành vi không xác định. Điều này có đúng không?Có an toàn khi sử dụng weak_ptr trong std :: set hoặc key of std :: map
Trả lời
Một trong những lý do std::owner_less
tồn tại là cung cấp thứ tự này và đảm bảo sự an toàn của nó khi có dấu chấm hết yếu. Logic của tôi là
Đầu tiên, định nghĩa về std::owner_less
operator() định nghĩa một trật tự yếu nghiêm ngặt theo quy định tại 25,4
dưới quan hệ tương đương xác định bởi
operator()
,!operator()(a, b) && !operator()(b, a)
, haishared_ptr
hoặcweak_ptr
trường hợp tương đương khi và chỉ khi họ chia sẻ quyền sở hữu hoặc cả hai đều trống.
Hai trường hợp là
- Họ chia sẻ cùng một đối tượng, mà trong thực tế có nghĩa là họ chia sẻ cùng một đối tượng tính tham khảo.
- Cả hai đều trống.
Bây giờ, tôi tin rằng sự nhầm lẫn là trong nhiệm kỳ thứ hai. Điều quan trọng là "trống" trong tiêu chuẩn có nghĩa là weak_ptr
không chia sẻ quyền sở hữu với bất kỳ đối tượng nào. Một lần nữa, các tiêu chuẩn quốc gia
constexpr weak_ptr() noexcept;
Effects: Tạo thời đối tượng rỗng
weak_ptr
.
Điều kiện sau:use_count() == 0
.weak_ptr(const weak_ptr& r) noexcept;
template<class Y> weak_ptr(const weak_ptr<Y>& r) noexcept;
template<class Y> weak_ptr(const shared_ptr<Y>& r) noexcept;
Yêu cầu: Các nhà xây dựng thứ hai và thứ ba sẽ không tham gia trong việc giải quyết tình trạng quá tải trừ khi
Y*
là mặc nhiên chuyển đổi thànhT*
.Hiệu ứng: Nếu
r
trống, hãy tạo đối tượng trốngweak_ptr
; nếu không, hãy tạo đối tượngweak_ptr
chia sẻ số quyền sở hữu vớir
và lưu trữ bản sao của con trỏ được lưu trữ trongr
.Điều kiện sau:
use_count() == r.use_count()
.
Swap được định nghĩa là trao đổi các trạng thái của hai weak_ptr
s, và nhiệm vụ được định nghĩa là sử dụng các nhà thầu trên cùng với một hoán đổi. Chúng là chìa khóa cần lưu ý ở đây là cách duy nhất để tạo một ô trống weak_ptr
là mặc định xây dựng hoặc sao chép/di chuyển/chỉ định một từ một số trống rỗng trước đây weak_ptr
hoặc shared_ptr
. Điều quan trọng cần lưu ý là bạn không thể nhận được số trống weak_ptr
bằng cách đơn giản là để cho số weak_ptr
hết hạn. Hết hạn weak_ptr
chỉ đơn giản là có use_count
bằng không. Là một vấn đề thực tế, khi một shared_ptr
được tạo, một đối tượng đếm tham chiếu phải được tạo ra, tách biệt với dữ liệu bằng cách sử dụng hàm tạo shared_ptr
hoặc trong cùng một cấp phát bộ nhớ khi sử dụng std::make_shared
. Khi số weak_ptr
được tạo từ số shared_ptr
, nó sẽ trỏ đến cùng cấu trúc điều khiển và số lượng tham chiếu đó. Khi shared_ptr
bị phá hủy, nó có thể phá hủy dữ liệu, nhưng đối tượng đếm tham chiếu phải duy trì cho đến khi tất cả các weak_ptr
chia sẻ quyền sở hữu đó sẽ bị xóa. Nếu không, weak_ptr
sẽ có tham chiếu trỏ chuột lơ lửng.
Vì vậy, tất cả điều này được thực hiện cùng nhau có nghĩa là nó là an toàn để sử dụng std::weak_ptr
khi họ quan trọng của một std::map
hoặc trong một std::set
, miễn là bạn sử dụng std::owner_less
để thực hiện đặt hàng. Các điều trên đảm bảo rằng thứ tự của weak_ptr
sẽ vẫn giữ nguyên ngay cả khi nó hết hạn trong khi nó nằm trong vùng chứa.
- 1. Sử dụng std shared_ptr làm std :: key map
- 2. Sử dụng std :: reference_wrapper trong std :: map
- 3. std :: weak_ptr: khóa hoặc shared_ptr constructor?
- 4. Sử dụng std :: reference_wrapper làm khóa trong std :: map
- 5. Sự khác nhau giữa std :: multimap <key, value> và std :: map <key, std :: set <value>>
- 6. Doxygen có thể nhận diện std :: shared_ptr hoặc std :: map
- 7. Có cách nào để giao nhau/diff một std :: map và std :: set?
- 8. std :: back_inserter cho std :: set?
- 9. sử dụng BOOST_FOREACH với std :: map
- 10. Khi nào tôi sử dụng node_type với std :: map :: insert?
- 11. std :: for_each qua std :: set, C++ 11
- 12. Gán nhiều giá trị để std :: mảng trong std :: map
- 13. temporaries Tránh trong std :: bản đồ/std :: tra cứu unordered_map với std :: string key
- 14. Dùng std :: string làm khóa cho std :: map
- 15. Tại sao không std :: weak_ptr có operator->?
- 16. An toàn chủ đề của C++ std Vùng chứa
- 17. Tại sao std :: hash không được định nghĩa cho std :: weak_ptr trong C++ 0x?
- 18. Tôi có nên sử dụng std :: default_random_engine hoặc tôi nên sử dụng std :: mt19937?
- 19. chỉ mục hoặc vị trí trong std :: set
- 20. Khi nào nên chọn std :: vector over std :: map cho dữ liệu khóa-giá trị?
- 21. Persistence of std :: bản đồ trong C++
- 22. Initialising std :: shared_ptr <std::map<>> sử dụng chuẩn bị tinh thần-init
- 23. Dễ dàng khởi tạo một std :: list of std :: strings?
- 24. Không có trình lặp cho Java khi sử dụng SWIG với C++ 's std :: map
- 25. khoảng cách giữa std :: set begin() và std :: set iterator trong O (logn)
- 26. std :: lock_guard hoặc std :: scoped_lock?
- 27. ưu điểm của std :: set vs vectơ hoặc bản đồ
- 28. C++ value_type không làm việc cho std :: tr1: tuple trong một std :: map
- 29. tham khảo như là chìa khóa trong std :: map
- 30. Có an toàn khi thay thế mảng tích hợp bằng mảng std/tr1/boost :: không?
Bạn có thể thêm kết luận vào câu trả lời này không? :) – Drax
@Drax: Chắc chắn rồi. Tôi đã viết muộn vào ban đêm và tôi đã bỏ lỡ những chi tiết nhỏ như thế. –
Đáng yêu, cảm ơn bạn :) – Drax