2016-01-11 10 views
14

in den 11 Beispielen ++ Boost.Asio C gibt es Schnipsel like the following:Warum erfassen Sie dies und Shared-Pointer-to-this in Lambdas?

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); 
     } 
     }); 
} 

Ich verstehe, warum die self Zeiger die Klasse am Leben zu halten (siehe this question) benötigt wird, aber ich verstehe nicht, warum die this Zeiger ist auch erfasst. Ist es nur so, dass der Autor do_write(length) anstelle von self->do_write(length) schreiben kann oder gibt es einen anderen Grund?

+1

In einem Wort: Bequemlichkeit. – sehe

Antwort

5

Ohne this erfasst, können Sie Methoden der Klasse nicht innerhalb des Lambda aufrufen (z. B. do_write). Oder greifen Sie auf Mitgliedsvariablen zu. Zugegeben, Sie könnten stattdessen schreiben self->do_write(), aber es ist sowohl weniger elegant und möglicherweise langsamer (wegen der shared_ptr beteiligt).

+1

Nur um das Geschwindigkeitsproblem zu erweitern: Antworten von [dieser Frage] (http://stackoverflow.com/questions/22295665/how-much-is-the-overhead-of-smart-pointers-compared-to-normal- Zeiger in c) scheinen darauf hinzuweisen, dass bei alten/schlechten Compilern der Dereferenzierung eines intelligenten Zeigers langsamer sein kann als bei der Dereferenzierung von rohen Zeigern, aber bei modernen Compilern sollte es fast keine Nachteile geben. – dshepherd

+0

@dshepherd: Fair genug, aber es ist wahrscheinlich noch langsamer mit Optimierungen deaktiviert (z. B. Debug-Modus). –

+0

@shep Ich weiß nicht: Dies ist ein Const-Zeiger auf ein leicht zu ermittelndes Objekt. Das shared ptr wird aus einem schwachen ptr erstellt, das im Objekt gespeichert ist, das initialisiert wurde, als das erste Mal ein shared ptr aus dem Objekt erstellt wurde. Ich kann mir nicht vorstellen, dass es keine Fälle gibt, in denen der Optimierer Probleme damit hat, ganz zu schweigen von der Tatsache, dass die Freigabe von diesem Null sein kann! – Yakk

2

Die Antwort dort ist ABSOLUTELY falsch! Sie sollten nicht beide passieren! Hier ist, wie Sie es tun sollten, basierend auf dem Code, ohne den Weg 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); 
     } 
     }); 
} 

Und tatsächlich, sollten Sie std::bind, nicht lambdas hierfür werden. Das würde Ihren Code kompakter machen.

+1

Die Antwort von Violet Giraffe scheint für mich vollkommen Sinn zu ergeben. Können Sie näher erläutern, wie es falsch ist und warum Ihres besser ist? – Quentin

+0

@Quentin Zitieren "Ohne diese erfasst, können Sie Methoden der Klasse nicht innerhalb des Lambda aufrufen". Das ist rein falsch. 'self' kann genau das tun, was' this' tut. Es ist auch falsch anzunehmen, dass 'shared_from_this' langsamer ist (obwohl er" potentiell "sagt, was eine nutzlose, defensive, fluidische Antwort ist). 'operator->' führt keine Überprüfungen durch, so dass die geringste Optimierung jeden Leistungsunterschied zunichte macht. Diese Antwort liefert keine nützlichen Informationen, sondern falsche Informationen, die auf Annahmen und Verallgemeinerungen beruhen. Tut mir leid, dass ich hart bin, aber ich bin überrascht. –

+0

Nach dem Lesen der Dokumentation sollte es in der Tat keine Performance-Implikationen geben. Sie verlieren jedoch den direkten Mitgliederzugriff (d. H. Weder 'this->' noch 'self>'). – Quentin