2014-04-22 16 views
7

Ci sono stati una serie di domande oggi per quanto riguarda std::weak_ptr e std::owner_less e il loro utilizzo nei contenitori associativi std::set e std::map. Esistono numerosi post che affermano che l'utilizzo di weak_ptr in un std::set non è corretto, poiché se il puntatore debole scade, sarà il comportamento non definito. È corretto?E 'sicuro usare un weak_ptr in uno std :: set o la chiave di std :: map

risposta

9

Uno dei motivi std::owner_less è fornire questo ordine e garantire la sua sicurezza in presenza di punti deboli in scadenza. Mia logica è

primo luogo, la definizione di std::owner_less

  • operatore() definisce un ordinamento debole rigorosa definita 25.4

    sotto la relazione di equivalenza definita da operator(), !operator()(a, b) && !operator()(b, a), due shared_ptr oppure le istanze weak_ptr sono equivalenti se e solo se condividono la proprietà o sono entrambe vuote.

I due casi sono

  1. Essi condividono lo stesso oggetto, che in pratica significa che condividono lo stesso oggetto conteggio di riferimento.
  2. Sono entrambi vuoti.

Ora, credo che la confusione sia finita nel secondo periodo. La chiave è che "vuoto" nello standard significa che lo weak_ptr non condivide la proprietà con alcun oggetto. Ancora una volta, gli stati standard

  • constexpr weak_ptr() noexcept;

    Effetti: costruisce un weak_ptr oggetto vuoto.
    Postconditions: 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;

    Richiede: Il secondo e terzo costruttori non devono partecipare alla risoluzione di sovraccarico a meno Y* è implicitamente convertibile in T*.

    Effetti: Se r è vuoto, costruisce un oggetto vuoto weak_ptr; altrimenti, costruisce un oggetto weak_ptr che condivide la proprietà con r e memorizza una copia del puntatore memorizzata in r.

    Postcondizioni: use_count() == r.use_count().

Swap è definito come scambiare gli stati dei due weak_ptr s, e assegnazione viene definita usando i costruttori sopra insieme ad uno scambio.

Essi chiave da notare qui è che l'unico modo per creare un vuoto weak_ptr è per difetto costruirlo, o copiare/spostare/assegnare una dall'precedentemente vuoto weak_ptr o shared_ptr. È anche importante notare che non è possibile ottenere uno weak_ptr vuoto semplicemente lasciando scadere il weak_ptr. Uno scaduto weak_ptr ha semplicemente uno use_count di zero.

In pratica, quando viene creato un shared_ptr, un oggetto conteggio di riferimento deve essere creato, sia separato dai dati utilizzando il costruttore shared_ptr, o nella stessa allocazione di memoria quando si utilizza std::make_shared. Quando un weak_ptr viene creato da quello shared_ptr, punta a quella stessa struttura di controllo e numero di riferimento. Quando lo shared_ptr viene distrutto, può distruggere i dati, ma l'oggetto conteggio di riferimento deve rimanere finché tutti i weak_ptr che condividono la proprietà vengono rimossi. In caso contrario, weak_ptr avrà un riferimento di puntatore pendente.

Quindi, tutto questo nel loro insieme significa che è sicuro da usare std::weak_ptr in quanto chiave di un std::map o in un std::set, fino a quando si utilizza std::owner_less per eseguire l'ordine. Quanto sopra garantisce che l'ordine di weak_ptr rimarrà lo stesso anche se scade mentre è nel contenitore.

+0

Puoi aggiungere una conclusione a questa risposta? :) – Drax

+0

@Drax: certo. L'ho scritto a tarda notte e ho perso alcuni piccoli dettagli del genere. –

+0

Bello, grazie :) – Drax

Problemi correlati