2016-05-30 5 views
2

Normalerweise würde ich einen Zyklus von shared_ptr s mit weak_ptr brechen. Aber ich kann nicht sehen, wie das in diesem Beispiel zu tun:Wie kann ich diesen Referenzzyklus std :: shared_ptr unterbrechen?

struct A; 
struct B; 
struct C; 
struct D; 

struct Cache { 
    std::shared_ptr<A> a; 
    std::shared_ptr<B> b; 
    std::shared_ptr<C> c; 
    std::shared_ptr<D> d; 
}; 

struct A { 
}; 

struct B { 
    // Same 'a' as in the Cache 
    std::shared_ptr<A> a; 
}; 

struct C { 
    // Holds a backreference to the cache 
    std::shared_ptr<Cache> cache; 
}; 

struct D { 
    // Same 'c' as in the cache 
    std::shared_ptr<C> c; 
}; 

Es gibt nie Zyklen zwischen dem A, B usw. Die einzigen Zyklen sind Rückreferenzierungen zum Cache. Die Cache muss am Leben bleiben, solange jemand (außer der Cache selbst) eine shared_ptr<C> hat, so dass nur die Verwendung weak_ptr<Cache> wird nicht funktionieren. Zum Beispiel:

std::shared_ptr<Cache> make_cache() { 
    auto cache = std::make_shared<Cache>(); 
    cache->a = std::make_shared<A>(); 
    cache->b = std::make_shared<B>(); 
    cache->b->a = cache->a; 
    cache->c = std::make_shared<C>(); 
    cache->c->cache = cache; 
    cache->d = std::make_shared<D>(); 
    cache->d->c = cache->c; 
    return cache; 
} 

void use_cache() { 
    auto a = make_cache()->a; 
    // No need to keep the Cache around 

    auto b = make_cache()->b; 
    // b->a must be valid 

    auto c = make_cache()->c; 
    // c->cache must be valid 

    auto d = make_cache()->d; 
    // d->c (and therefore d->c->cache, etc.) must be valid 
} 

Ich verstehe, dass in der Regel würde dies einen Garbage Collector erfordern, aber ich bin in diesem speziellen Fall der Hoffnung, es gibt einige Tricks, die mit shared_ptr ‚s aliasing constructor (8) oder etwas getan werden können.

+1

Versteckte zyklische Referenzen können tatsächlich nicht mit den Standard-C++ 'shared_ptr' /' weak_ptr'-Idiomen gelöst werden. Sie müssen Ihr Design ändern. –

+4

Da 'c' und' cache' immer aufeinander verweisen, sollten Sie vielleicht eine neue Klasse 'CacheWithData' erstellen, die' Cache' und 'C' enthält und' C :: cache' und 'Cache :: c' Verwenden Sie die Referenzzahl ('std :: shared_ptr (cwd, & cwd-> c)') –

Antwort

0

„Der Cache muss am Leben, so lange wie jemand bleiben (mit Ausnahme der Cache selbst) ein shared_ptr<C> hat.“

Dies argumentiert, dass C die ultimative Lebensdauer der gesamten Struktur steuert. Daher sollte der Cache nicht in C zusammengesetzt werden?

+0

'C' muss auch am Leben bleiben, solange jemand eine' shared_ptr 'hat. Keiner ist besonders. –

+0

@TavianBarnes sagen Sie, dass, solange ein gemeinsamer Zeiger auf einen Teil der Struktur gültig ist, die gesamte Struktur gültig ist? –

+0

Im Idealfall, ja, das sage ich. –

Verwandte Themen