2010-03-08 12 views
13

Per motivi legacy, ho bisogno di usare puntatori intrusivi, poiché ho bisogno della capacità di convertire i puntatori grezzi in puntatori intelligenti.C'è una spinta :: weak_intrusive_pointer?

Tuttavia ho notato che non c'è un debole indicatore intrusivo per aumentare. Ne ho trovato parlare nella lista dei thread di boost, ma niente di concreto.

Qualcuno sa di un'implementazione thread safe del puntatore intrusivo debole?

Grazie Rich

risposta

10

Non ha alcun senso.

Per elaborare: weak_ptr punti per la stessa istanza di un oggetto counter fare shared_ptr. Quando lo shared_ptr esce dal campo di applicazione, l'istanza di counter rimane (con un conteggio efficace a 0), che consente alle istanze weak_ptr di verificare che puntino effettivamente a un oggetto liberato.

Con il conteggio intrusivo, il contatore è integrato nell'oggetto. Quando il conteggio raggiunge 0, l'oggetto viene solitamente riciclato o cancellato ... ma il punto è che il contatore non è più disponibile. La logica è che ciò consente una memorizzazione più efficiente (1 singolo pezzo) e una maggiore velocità (località cache).

Se è necessario il conteggio dei riferimenti deboli e non si cura dei vantaggi del conteggio intrusivo, è possibile utilizzare una combinazione di shared_ptr e weak_ptr.

L'idea è di deassociare il contatore dagli oggetti.

class Counted 
{ 
    // bla 
private: 
    boost::shared_ptr<int> mCounter; 
}; 

Ora si può tornare maniglie deboli:

class WeakHandle 
{ 
public: 
    explicit WeakHandle(Counted& c): mCounter(c.mCounter), mObject(&c) {} 

    bool expired() const { return mCounter.expired(); } 

private: 
    boost::weak_ptr<int> mCounter; 
    Counted* mObject; 
}; 

Qui, deassociate la durata del contatore del ciclo di vita di un oggetto, in modo che possa sopravvivere alla distruzione dell'oggetto ... parzialmente. Rendendo così possibile lo weak_ptr efficace.

E, naturalmente, utilizzando shared_ptr e weak_ptr questo è thread-safe;)

+0

La mia idea è di incorporare l'oggetto condiviso utilizzato da ptr condiviso e ptr debole all'interno dell'oggetto host e intrusive_weak_ptr (se esistesse) lo userebbe nello stesso modo di weak_ptr. Ho ancora bisogno della funzionalità di cancellare l'oggetto quando non ci sono più riferimenti. Inoltre ho bisogno di prendere riferimenti deboli. – Rich

+0

Penso che tu non abbia capito il mio punto: questo è esattamente ciò che propongo. L'oggetto 'Contato' è contato" intrusivamente ", ho appena cambiato il contatore da un intero semplice a un puntatore a un numero intero. Per quanto riguarda il tuo 'intrusive_weak_ptr' è proprio quello che ho chiamato' WeakHandle'. –

+0

Ah penso di essere con te. Quindi userei un puntatore intrusivo come al solito, tuttavia quando viene invocato intrusive_ptr_add_ref, faccio riferimento a int dal puntatore condiviso come mio conteggio. Quando questo raggiunge zero, l'oggetto viene liberato, tuttavia qualsiasi riferimento debole mantiene un puntatore all'int. È corretto? – Rich

4

attuazione attuale della puntatore intrusive sta utilizzando contatore di riferimento. Quindi, eliminando l'oggetto delete, cancelli anche il contatore, quindi weak_intrusive_pointer non saprà mai che l'oggetto è stato cancellato.

Se è necessario ottenere weak_ptr da this, probabilmente si cerca boost::enable_shared_from_this<T>.

3

non mi piace nessuna delle risposte precedenti così:

No, non so di un'implementazione, ma penso che sia possibile. L'implementazione standard di shared_ptr contiene due riferimenti di riferimento, uno per il "forte" e uno per i riferimenti "deboli" e un puntatore al referente. In un'implementazione intrusive_ptr il conteggio forte deve essere parte dell'oggetto, ma il debole non può essere. Quindi, sembra che potresti creare un intrusive_ptr "debole".

Definire un debole puntatore helper:

template<class X> 
class intrusive_ptr_weak_helper { 
    long weak_ref_count; 
    X *target_instance; 
}; 

quindi registrare che nell'oggetto accanto al conteggio di riferimento:

struct X { 
    ... 
    intrusive_ptr_weak_helper *ref_weak_helper; 
    ... 
    long ref_count; 
    ... 
}; 

Quando si costruisce X:

ref_count = 0; 
ref_weak_helper = NULL; 

Il "forte" pointer, intrusive_strong_ptr, è identico a intrusive_ptr, fino a quando non si verifica la cancellazione. Quando il forte conteggio ref va a zero (prima che si verifichi l'eliminazione):

if (ref_weak_helper != NULL) { 
    if (ref_weak_helper->weak_ref_count == 0) 
     delete ref_weak_helper; 
    else 
     ref_weak_helper->target_instance = NULL; 
} 

Il "debole" versione, intrusive_weak_ptr, registra il puntatore al aiutante deboli, la manipolazione che contano di riferimento, e l'accesso l'oggetto di destinazione tramite il target_instance puntatore. Quando weak_ref_count decrementa a zero lo stato di target_instance determina se l'helper viene eliminato o meno.

Mancano molti dettagli (ad esempio, problemi di concorrenza) ma si tratta di un mix di shared_ptr e intrusive_ptr. Mantiene i vantaggi di base dell'intrusive_ptr (ottimizzazione della cache, riutilizzo del conteggio degli invii di terze parti (forte), puntatori dei puntatori forti e deboli sono di dimensioni puntatore) mentre aggiungono lavoro extra principalmente nel percorso di riferimento debole.