2014-04-22 8 views
7

Odnotowano szereg pytań dotyczących std::weak_ptr dzisiaj i std::owner_less i ich zastosowanie w pojemnikach asocjacyjnych std::set i std::map. Istnieje pewna liczba postów stwierdzających, że używanie weak_ptr w std::set jest niepoprawne, ponieważ w przypadku wygaśnięcia słabego wskaźnika będzie to niezdefiniowane zachowanie. Czy to jest poprawne?Czy można bezpiecznie używać weak_ptr w std :: set lub klucz std :: map

Odpowiedz

9

Jednym z powodów, dla których istnieje std::owner_less jest dostarczenie tego zamówienia i zagwarantowanie jego bezpieczeństwa w obecności wygasających słabych wskaźników. My logika

pierwsze definicja std::owner_less

  • operatora() tworzy ścisłe słabą kolejność jak określono w 25,4

    pod stosunku równoważnikowym określonej przez operator(), !operator()(a, b) && !operator()(b, a) dwa shared_ptr lub weak_ptr wystąpienia są równoważne wtedy i tylko wtedy, gdy mają wspólną własność lub są puste.

Oba przypadki są

  1. Dzielą ten sam przedmiot, co w praktyce oznacza, że ​​dzielą ten sam obiekt licznika odwołań.
  2. Są puste.

Sądzę, że zamieszanie dotyczy drugiego okresu. Kluczem jest to, że "pusty" w standardzie oznacza, że ​​weak_ptr nie współdzieli własności z żadnym obiektem. Ponownie, standardowe stany

  • constexpr weak_ptr() noexcept;

    Działanie: Tworzy pusty weak_ptr obiekt.
    Postgrecje: 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;

    Wymaga: Drugi i trzeci konstruktorzy nie bierze udziału w rozdzielczości przeciążenia chyba Y* jest niejawnie zamienny do T*.

    Efekty: Jeśli r jest pusty, konstruuje pusty obiekt weak_ptr; w przeciwnym razie konstruuje obiekt weak_ptr, który dzieli własność z r i przechowuje kopię wskaźnika przechowywaną w r.

    Postgrecje: use_count() == r.use_count().

Zmienne jest zdefiniowane jako zamiany stany obu weak_ptr s, a przypisanie określono z zastosowaniem konstruktory powyżej wraz z wymiany.

klucz one zwrócić uwagę jest to, że jedynym sposobem, aby utworzyć pusty weak_ptr jest domyślnie skonstruować go lub kopia/ruch/przypisać jedną z poprzednio pusty weak_ptr lub shared_ptr. Ważne jest również, aby pamiętać, że nie można uzyskać pustego weak_ptr, po prostu wygasając weak_ptr. Wygasły weak_ptr ma po prostu zerowe zero.

W praktyce, gdy shared_ptr tworzony jest obiekt liczba odniesienia mają być utworzone albo oddzielone od danych z wykorzystaniem konstruktora shared_ptr lub w samej alokacji pamięci, gdy stosuje std::make_shared. Kiedy weak_ptr skonstruowany jest z tego shared_ptr, wskaże tę samą strukturę kontrolną i liczbę odwołań. Po zniszczeniu kodu shared_ptr może on zniszczyć dane, ale obiekt licznika odniesień musi pozostać, dopóki nie zostanie usunięty cały udział własności. W przeciwnym razie, weak_ptr będzie mieć odniesienie wskaźnika zwisającego.

Tak, wszystko to razem wzięte oznacza, że ​​jest bezpieczny w użyciu std::weak_ptr jako klucz they z std::map lub w std::set, tak długo jak używasz std::owner_less wykonać kolejność. Powyższe gwarantuje, że zamówienie weak_ptr pozostanie niezmienione, nawet jeśli wygasa, gdy jest w kontenerze.

+0

Czy możesz dodać wniosek do tej odpowiedzi? :) – Drax

+0

@Drax: Jasne rzeczy. Napisałem to późno w nocy i straciłem trochę szczegółów. –

+0

Piękny, dziękuję :) – Drax