Domanda

mi sono imbattuto in enable_shared_from_this durante la lettura degli esempi Boost.Asio e dopo aver letto la documentazione Sto ancora perso per come questo dovrebbe essere utilizzato in modo corretto. Qualcuno può per favore mi dia un esempio e / o e la spiegazione di quando si utilizza questa classe ha un senso.

È stato utile?

Soluzione

E 'consente di ottenere un'istanza shared_ptr valida per this, quando tutto ciò che hai è this. Senza di essa, si avrebbe alcun modo di ottenere un shared_ptr a this, a meno che non hai già avuto uno come membro. Questo esempio dalla documentazione spinta per enable_shared_from_this :

class Y: public enable_shared_from_this<Y>
{
public:

    shared_ptr<Y> f()
    {
        return shared_from_this();
    }
}

int main()
{
    shared_ptr<Y> p(new Y);
    shared_ptr<Y> q = p->f();
    assert(p == q);
    assert(!(p < q || q < p)); // p and q must share ownership
}

Il metodo f () restituisce un shared_ptr valida, anche se non aveva alcuna istanza membro. Si noti che non si può semplicemente fare questo:

class Y: public enable_shared_from_this<Y>
{
public:

    shared_ptr<Y> f()
    {
        return shared_ptr<Y>(this);
    }
}

Il puntatore condivisa che questa tornata avrà un conteggio di riferimento diverso da quello "corretto" uno, e uno di loro finirà per perdere e in possesso di un riferimento penzoloni quando l'oggetto viene eliminato.

enable_shared_from_this è diventata parte del C ++ 11 standard. È inoltre possibile ottenere da lì oltre che da spinta.

Altri suggerimenti

dall'articolo Dr Dobbs su puntatori deboli, penso che questo esempio è più facile da capire (fonte: http: // drdobbs .com / cpp / 184402026 ):

... il codice come questo non funziona correttamente:

int *ip = new int;
shared_ptr<int> sp1(ip);
shared_ptr<int> sp2(ip);

Nessuno dei due oggetti shared_ptr sa circa l'altra, in modo che entrambi cercheranno di rilasciare la risorsa quando vengono distrutti. Che di solito porta a problemi.

Allo stesso modo, se una funzione di membro ha bisogno di un oggetto shared_ptr che possiede l'oggetto che viene chiamato in poi, è possibile non solo creare un oggetto al volo:

struct S
{
  shared_ptr<S> dangerous()
  {
     return shared_ptr<S>(this);   // don't do this!
  }
};

int main()
{
   shared_ptr<S> sp1(new S);
   shared_ptr<S> sp2 = sp1->dangerous();
   return 0;
}

Questo codice ha lo stesso problema come l'esempio precedente, anche se in una forma più sottile. Quando si è costruito, l'oggetto shared_pt sp1r proprietario della risorsa appena allocato. Il codice all'interno della funzione membro S::dangerous non sa su quell'oggetto shared_ptr, quindi l'oggetto shared_ptr che restituisce distinto da sp1. Copiare il nuovo oggetto shared_ptr a sp2 non aiuta; quando sp2 va fuori del campo di applicazione, che rilascerà la risorsa, e quando sp1 va fuori del campo di applicazione, che rilascerà nuovamente la risorsa.

Il modo per evitare questo problema è quello di utilizzare la enable_shared_from_this modello di classe. Il modello prende un argomento di tipo di modello, che è il nome della classe che definisce la risorsa gestita. Quella classe deve, a sua volta, essere derivato pubblicamente dal modello; in questo modo:

struct S : enable_shared_from_this<S>
{
  shared_ptr<S> not_dangerous()
  {
    return shared_from_this();
  }
};

int main()
{
   shared_ptr<S> sp1(new S);
   shared_ptr<S> sp2 = sp1->not_dangerous();
   return 0;
}

Quando si esegue questa operazione, tenere a mente che l'oggetto su cui si chiama shared_from_this deve essere di proprietà di un oggetto shared_ptr. Questo non funziona:

int main()
{
   S *p = new S;
   shared_ptr<S> sp2 = p->not_dangerous();     // don't do this
}

Ecco la mia spiegazione, dal punto di vista dadi e bulloni (risposta in alto non ha 'click' con me). * Si noti che questo è il risultato di indagare la fonte per shared_ptr e enable_shared_from_this che viene fornito con Visual Studio 2012. Forse altri compilatori implementano enable_shared_from_this diversamente ... *

enable_shared_from_this<T> aggiunge un'istanza weak_ptr<T> privato a T che detiene il ' unico vero riferimento count ' per l'istanza di T.

Quindi, quando si crea prima un shared_ptr<T> su un nuovo T *, che weak_ptr interna T * s 'viene inizializzato con un refcount di 1. Il nuovo shared_ptr appoggia sostanzialmente su questo weak_ptr.

T può allora, nei suoi metodi, chiamare shared_from_this per ottenere un'istanza di shared_ptr<T> che capiscono sullo stesso riferimento memorizzato internamente conteggio . In questo modo, si ha sempre un posto in cui ref-count di T* viene memorizzato invece di avere più istanze shared_ptr che non conoscono l'un l'altro, e ognuno pensa che sono il shared_ptr che si occupa di ref-conteggio T e l'eliminazione quando loro ref-count raggiunge lo zero.

Si noti che l'utilizzo di un boost :: intrusive_ptr non soffrono di questo problema. Questo è spesso un modo più conveniente per aggirare questo problema.

E 'esattamente lo stesso in C ++ 11 e versioni successive:. E' per attivare la capacità di restituire this come puntatore condiviso dal this ti dà un puntatore prime

In altre parole, si consenta di attivare il codice come questo

class Node {
public:
    Node* getParent const() {
        if (m_parent) {
            return m_parent;
        } else {
            return this;
        }
    }

private:

    Node * m_parent = nullptr;
};           

in questo modo:

class Node : std::enable_shared_from_this<Node> {
public:
    std::shared_ptr<Node> getParent const() {
        std::shared_ptr<Node> parent = m_parent.lock();
        if (parent) {
            return parent;
        } else {
            return shared_from_this();
        }
    }

private:

    std::weak_ptr<Node> m_parent;
};           

Un altro modo è quello di aggiungere un membro weak_ptr<Y> m_stub nella class Y. Quindi scrivere:

shared_ptr<Y> Y::f()
{
    return m_stub.lock();
}

Utile quando non è possibile modificare la classe che si sta derivanti da (ad esempio estendendo biblioteca di altre persone). Non dimenticate di inizializzare il membro, ad esempio, da m_stub = shared_ptr<Y>(this), la sua è valida anche durante un costruttore.

E 'OK se ci sono più stub come questa in gerarchia di ereditarietà, non impedirà distruzione dell'oggetto.

Modifica Come giustamente rilevato dalla Nobar dell'utente, il codice distruggerebbe oggetto Y quando il compito è finito e variabili temporanee vengono distrutti. Quindi la mia risposta non è corretta.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top