2014-11-23 15 views
9

Ho letto che i punti deboli possono essere utilizzati per interrompere i riferimenti ciclici.Come interrompere il riferimento ciclico shared_ptr utilizzando weak_ptr

Si consideri il seguente esempio di un riferimento ciclico

struct A 
{ 
boost::shared_ptr<A> shrd_ptr; 
}; 


boost::shared_ptr<A> ptr_A(boost::make_shared<A>()); 
boost::shared_ptr<A> ptr_b(boost::make_shared<A>()); 
ptr_A->shrd_ptr = ptr_b; 
ptr_b->shrd_ptr = ptr_A; 

Ora qui sopra è un caso di riferimento ciclico e volevo sapere come posso rompere il riferimento ciclico sopra utilizzando weak_ptr?

Aggiornamento: Sulla base di suggerimento ricevuto mi si avvicinò con la seguente:

struct A 
{ 
    boost::weak_ptr<A> wk_ptr; 
}; 

    boost::shared_ptr<A> ptr_A (boost::make_shared<A>()); 
    boost::shared_ptr<A> ptr_B (boost::make_shared<A>()); 
    ptr_A->wk_ptr = ptr_B; 
    ptr_B->wk_ptr = ptr_A; 

Sarà questo l'approccio corretto?

+1

Cambia 'A :: shrd_ptr' in' boost :: weak_ptr' e tieni premuto 'shared_ptr' da qualche altra parte. –

risposta

23

Il classico esempio di riferimenti ciclici è dove si hanno due classi A e B dove A ha un riferimento a B che ha un riferimento a A:

#include <memory> 
#include <iostream> 

struct B; 
struct A { 
    std::shared_ptr<B> b; 
    ~A() { std::cout << "~A()\n"; } 
}; 

struct B { 
    std::shared_ptr<A> a; 
    ~B() { std::cout << "~B()\n"; } 
}; 

void useAnB() { 
    auto a = std::make_shared<A>(); 
    auto b = std::make_shared<B>(); 
    a->b = b; 
    b->a = a; 
} 

int main() { 
    useAnB(); 
    std::cout << "Finished using A and B\n"; 
} 

Se entrambi i riferimenti sono shared_ptr allora che dice A ha la proprietà di B e B ha la proprietà di A, che dovrebbe suonare il campanello di allarme. In altre parole, A mantiene vivo B e B mantiene vivo il A.

In questo esempio le istanze a e b vengono utilizzati solo in funzione useAnB() così vorremmo loro di essere distrutti quando la funzione termina, ma come si può vedere quando si esegue il programma i distruttori non vengono chiamati.

La soluzione è decidere chi possiede chi. Diciamo A possiede B ma B non possiede A poi sostituiamo il riferimento a A in B con un weak_ptr in questo modo:

struct B { 
    std::weak_ptr<A> a; 
    ~B() { std::cout << "~B()\n"; } 
}; 

Poi se corriamo il programma vediamo che a e b sono distrutte come ci aspettiamo .

Live demo

Edit: Nel tuo caso, l'approccio hai suggerito sembra perfettamente valido. Prendi la proprietà da A e qualcos'altro possiede il A s.

+0

Una risposta molto buona - peccato solo dargli un +1 –

+0

il problema (riferimento ciclico) rimarrà se in seguito creeremo shared_ptr da a.lock()? –

+1

@Explorer_N Fornendo 'B' non si tiene su un' shared_ptr' creato da 'a.lock()' in modo permanente quindi è OK. [Ecco una versione estesa della demo live] (http://melpon.org/wandbox/permlink/mdIkQ3QbFhaskdro) che include un esempio di utilizzo di 'a.lock()'. –

Problemi correlati