2014-04-22 17 views
7

Có một số câu hỏi hôm nay về std::weak_ptrstd::owner_less và cách sử dụng chúng trong các vùng chứa liên kết std::setstd::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

9

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), hai shared_ptr hoặc weak_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à

  1. 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.
  2. 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ành T*.

    Hiệu ứng: Nếu r trống, hãy tạo đối tượng trống weak_ptr; nếu không, hãy tạo đối tượng weak_ptr chia sẻ số quyền sở hữu với r và lưu trữ bản sao của con trỏ được lưu trữ trong r.

    Đ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.

+0

Bạn có thể thêm kết luận vào câu trả lời này không? :) – Drax

+0

@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ế. –

+0

Đáng yêu, cảm ơn bạn :) – Drax

Các vấn đề liên quan