2016-01-11 14 views
14

Nel Boost.asio C++ 11 esempi ci sono frammenti like the following:Perché catturare questo e condiviso-pointer-to-this in lambda?

void do_read() 
{ 
    auto self(shared_from_this()); 
    socket_.async_read_some(boost::asio::buffer(data_, max_length), 
     [this, self](boost::system::error_code ec, std::size_t length) 
     { 
     if (!ec) 
     { 
      do_write(length); 
     } 
     }); 
} 

capisco perché il puntatore self è necessaria per mantenere in vita (vedi this question) la classe, ma non capisco il motivo per cui il Il puntatore this è anche catturato. È così che l'autore può scrivere do_write(length) invece di self->do_write(length) o c'è un altro motivo?

+1

In una parola: convenienza. – sehe

risposta

5

Senza this catturato, non è possibile chiamare i metodi della classe dall'interno del lambda (ad esempio do_write). O accedere alle variabili membro. Concesso, si potrebbe invece scrivere self->do_write(), ma è sia meno elegante e potenzialmente più lento (a causa del shared_ptr coinvolto).

+1

Solo per espandere il problema di velocità: risposte da [questa domanda] (http://stackoverflow.com/questions/22295665/how-much-is-the-overhead-of-smart-pointers-compared-to-normal- pointers-in-c) sembra indicare che su dereferenziatori di vecchi e cattivi compilatori un puntatore intelligente potrebbe essere più lento nel dereferenziare i puntatori grezzi, ma non ci dovrebbe essere quasi nessuna penalità sui compilatori moderni. – dshepherd

+0

@dshepherd: abbastanza corretto, ma probabilmente è ancora più lento con le ottimizzazioni disattivate (ad esempio la modalità di debug). –

+0

@shep Non so: questo è un puntatore const per un oggetto facile da determinare. Il ptr condiviso è costruito da un ptr debole memorizzato nell'oggetto, inizializzato la prima volta che un ptr condiviso è stato creato dall'oggetto. Non riesco a immaginare che non ci siano casi in cui l'ottimizzatore ha problemi con quello, per non parlare del fatto che ciò che è condiviso da questo può essere nullo! – Yakk

2

La risposta data laggiù è errata errata! Non dovresti passare entrambi! Ecco come si dovrebbe fare, in base al codice, senza passare this:

void do_read() 
{ 
    auto self(shared_from_this()); 
    socket_.async_read_some(boost::asio::buffer(data_, max_length), 
     [self](boost::system::error_code ec, std::size_t length) 
     { 
     if (!ec) 
     { 
      self->do_write(length); 
     } 
     }); 
} 

E in realtà, si dovrebbe utilizzare std::bind, non lambda per questo. Ciò renderebbe il tuo codice molto più compatto.

+1

La risposta di Violet Giraffe sembra avere perfettamente senso per me. Potresti approfondire come è sbagliato e perché il tuo è migliore? – Quentin

+0

@Quentin Quoting "Senza questo catturato, non puoi chiamare i metodi della classe dall'interno del lambda". Questo è puramente sbagliato. 'self' può fare esattamente cosa' questo' fa. Inoltre è sbagliato assumere che 'shared_from_this' sia più lento (anche se ha detto" potenzialmente ", che è una risposta inutile, difensiva e fluida). 'operator->' non esegue alcun controllo, quindi l'ottimizzazione minima ucciderà qualsiasi differenza nelle prestazioni. Questa risposta non fornisce alcuna informazione utile, ma un'informazione errata basata su ipotesi e generalizzazioni. Scusa per essere severo, ma sono sorpreso. –

+0

Dopo aver letto la documentazione, non ci dovrebbero essere implicazioni di perfomance. Tuttavia, perdi l'accesso diretto ai membri (ad esempio no 'this->' né 'self->'). – Quentin

Problemi correlati