2016-07-17 88 views
7

Se ho un std::shared_ptr<Foo> con un deleter personalizzato, è garantito che tutti i puntatori deboli associati sono visti come scaduti dal deleter? (Lo apprezzerei molto se potessi citare sezioni rilevanti nello standard).I puntatori deboli sono garantiti per essere scaduti quando viene eseguito il deleter std :: shared_ptr?

In altre parole, l'affermazione sotto è garantita per non sparare?

std::weak_ptr<Foo> weak; 
std::shared_ptr<Foo> strong{ 
    new Foo, 
    [&weak] (Foo* f) { 
    assert(weak.expired()); 
    delete f; 
    }, 
}; 

weak = strong; 
strong.reset(); 
+1

Bene, il contatore di utilizzo sarà zero prima che venga chiamato il deleter e [questo riferimento 'scaduto'] (http://en.cppreference.com/w/cpp/memory/weak_ptr/expired) dice che è" Equivalente a 'use_count() == 0'". Il riferimento non è autorevole, è necessario passare attraverso le specifiche per trovare la risposta definitiva (bozze degli standard C++ 11, C++ 14 e C++ 17 sono tutte disponibili gratuitamente, l'ultima bozza prima della ratifica è buona abbastanza). –

+0

concordato. Ma una risposta definitiva dallo standard è esattamente quello che sto chiedendo. :-) Non ne ho ancora trovato uno per me stesso. – jacobsa

+2

Penso che questo sia implicito: se la tua asserzione non fosse vera, allora potresti sostituirla con 'weak.lock()' (e magari spostare la proprietà), e quindi il distruttore per l'oggetto condiviso verrebbe eseguito due volte. –

risposta

2

Non c'è apparentemente nulla nello standard C++ 14 che lo garantisca. Ora ho aperto uno defect report per lo standard che copre il problema.

+0

Il rapporto sui difetti è stato aggiornato. Sembrano considerare questo come non un difetto: i deletatori non dovrebbero preoccuparsi di cose del genere, e l'onere di implementazione per consentirlo sarebbe apparentemente più di quello che vogliono aggiustarlo. –

+0

Sì, l'ho visto. Onestamente non capisco quale sia l'onere di implementazione a cui si riferiscono. – jacobsa

8

Lo standard non garantisce nulla. Per distruttore shared_ptr s', la specifica dice soltanto:

  • Se *this è di proprietà vuoto o quote con un altro shared_ptr istanza (use_count()> 1), non ci sono effetti collaterali.
  • In caso contrario, se *this possiede un oggetto p e un deleter d, d(p) viene chiamato.
  • In caso contrario, *this possiede un puntatore p e viene chiamato p.

    [Nota: Dal momento che la distruzione della *this diminuisce il numero di istanze che condividono la proprietà di * questo per uno, dopo *this è stato distrutto tutti shared_ptr istanze che proprietà condivisa con *this segnalerà un use_count() che è uno in meno rispetto al suo precedente valore. nota -end]

E reset è definito in termini di scambio di un shared_ptr in una temporanea, che viene poi distrutti.

Quindi la specifica garantisce che lo stato di use_count sarà pari a zero dopo il il distruttore è terminato. Esattamente quando durante quel processo è impostato su 0 non è specificato.

+1

Grazie, questa è stata anche la mia comprensione del problema, ma ne hai colto il cuore.:-) Credo che dovrò fare affidamento sul fatto che sarebbe molto pericoloso per un'implementazione fare qualsiasi altra cosa (perché potresti resuscitare un 'std :: shared_ptr ' a un oggetto che è attualmente cancellato). – jacobsa

+1

@jacobsa: è possibile presentare un rapporto sui difetti su di esso. Potrebbero avere una correzione per la formulazione di C++ 17. –

+2

Grazie, ho archiviato un rapporto sui difetti. – jacobsa

Problemi correlati