2014-11-06 12 views
6

Ho una struttura a oggetti costituita da shared_ptr s, più weak_ptr s per evitare la circolarità. I puntatori grezzi sono un no-go come boost::serialization ha bisogno di ripristinare i puntatori condivisi e deboli durante la deserializzazione tramite il rilevamento degli oggetti come tempo di serializzazione. I modelli di vita dell'oggetto sono complessi (simulazione di particelle) ma interamente prevedibili. Ogni volta che uso weak_ptr::lock(), sono sicuro che il puntatore è ancora valido. In genere, utilizzo lock().get() in quanto ho bisogno dell'oggetto per un tempo molto breve.Portable hack per individuare il puntatore raw da weak_ptr

Ora, lock().get() ha implicazioni sulle prestazioni, poiché incrementerà il conteggio condiviso (in lock()) e quindi diminuirà poco dopo (il valore temporaneo shared_ptr è stato distrutto).

Questo boost.devel post dal 2002 dice che mentre weak_ptr è stato in fase di sviluppo, la funzionalità di accesso al puntatore prima direttamente è stato considerato (da nominare unsafe_get o leak), ma non sono mai arrivati ​​alla realizzazione vera e propria. La sua assenza costringe il programmatore a utilizzare l'interfaccia subottimale in determinate condizioni.

Ora, la domanda è come per emulare il unsafe_get/leak, in altre parole, ottenere il puntatore prima da weak_ptr, non valida a rischio del programmatore, solo la lettura (non scrivere) i dati. Posso immaginare che alcuni trucchi come scoprire l'offset del puntatore grezzo all'interno di shared_ptr o simili farebbero il lavoro.

Sto usando boost::shared_ptr, ma la soluzione potrebbe funzionare anche per C++ 11 std::shared_ptr.

+2

Una buona domanda, ma suona onestamente come i puntatori grezzi sarebbe l'affare migliore qui. Gestisci gli oggetti separatamente (ad esempio raggruppa tutte le tue particelle in un contenitore) e passa intorno a indicatori deboli. –

+0

Penso che anche se usi l'oggetto per un breve periodo, dovresti tenere premuto il comando 'shared_ptr' mentre lo stai usando:' auto s = w.lock(); if (s) s-> doSomething(); 'Penso che usare' lock(). get() 'sia una cattiva pratica e non più veloce. È possibile che l'azione stessa dell'uso del puntatore possa effettivamente innescare l'ultimo 'shared_ptr' da morire. –

+1

Se si conosce il punto debole della vita degli oggetti senza un '.lock()' non usare 'weak_ptr'. Hai provato che questo è un collo di bottiglia per le prestazioni come una parte? – Yakk

risposta

3

Ti suggerisco di mantenere sia un weak_ptr sia un puntatore raw e utilizzare il puntatore raw direttamente come ottimizzazione quando sai che è sicuro farlo. È possibile concludere il weak_ptr e il puntatore raw associato in una classe che ha un unsafe_get se lo si desidera.

+1

Una nota importante è che è perfettamente valido per archiviare, utilizzare e aggirare puntatori e riferimenti grezzi anche dal C++ 11 a patto che quei puntatori non capiscano di "possedere" o gestire la durata dell'oggetto - la regola per la sicurezza è che devi sapere che alcuni "proprietari" (come un 'shared_ptr' per lo stesso oggetto) li sopravvive. Ovviamente un 'weak_ptr' non possiede l'oggetto a cui fa riferimento, quindi ci sono dei problemi lì se non si è sicuri della durata di quell'oggetto - è possibile che qualche altro codice possa distruggere l'ultimo' shared_ptr' a quel Oggetto 'weak_ptr'-referenced? – Steve314

+1

Senza dubbio è per questo che non esiste un 'unsafe_lock' nello standard. L'uso di 'lock(). Get()' (cioè non mantenere 'shared_ptr' finché si utilizza il puntatore raw) è anche piuttosto fragile. – Steve314

+0

@ Steve314: OT: Non penso che sia il caso di C++ di limitarne uno a causa di possibili pericoli. Sono d'accordo che non è buono incoraggiare pratiche pericolose, ma non includere qualcosa perché ** potrebbe ** essere abusato è un po 'genitorialità. – eudoxos

5

Dato che hai chiesto un attacco portatile.

Una parte divertente di codice trovato in boost's weak_ptr.hpp è:

template<class T> class weak_ptr 
{ 
    ... 

public: 

    ... 

// Tasteless as this may seem, making all members public allows member templates 
// to work in the absence of member template friends. (Matthew Langston) 

#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS 

private: 

    template<class Y> friend class weak_ptr; 
    template<class Y> friend class shared_ptr; 

#endif 

    element_type * px;   // contained pointer 
    boost::detail::weak_count pn; // reference counter 

}; // weak_ptr 

Il che significa che se si compila spinta con l'opzione BOOST_NO_MEMBER_TEMPLATE_FRIENDS, voi pubblicamente avere accesso al membro px di weak_ptr che sembra essere un puntatore RAW al tipo di elemento.

+1

Non sono sicuro di quanto questo sia a prova di futuro ... qual è la politica di Boost sulla rottura della compatibilità binaria nelle versioni future? Perché se lo permettono (molto valido) allora questo hack purtroppo non è portatile. E non funzionerà nemmeno con 'std :: weak_ptr'. –

+1

@KonradRudolph Beh, se fosse a prova di futuro, non sarebbe un trucco. Ma in un dato momento questo hack è portatile quanto le librerie di boost, può rompersi solo quando si aggiorna la versione boost, ma come qualsiasi altra funzione normale da boost. – Drax

+0

Un'altra opzione potrebbe essere quella di sfruttare l'amicizia: specializzare esplicitamente un weak_ptr usando un tipo appositamente designato Y, quindi accedere a px: 'template <> weak_ptr {/ * friend of weak_ptr * /};'. L'amico modello è una backdoor di accesso generica. – NicholasM

Problemi correlati