2016-01-11 10 views
14

W latach Boost.asio C++ 11 przykładów są fragmenty like the following:Dlaczego przechwytywać to, a także współdzielić wskaźnik do tego w lambdach?

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

rozumiem dlaczego jest potrzebny wskaźnik self zachować klasę żywy (patrz this question), ale nie rozumiem, dlaczego this Wskaźnik jest również przechwycony. Czy to jest tak, że autor może napisać do_write(length) zamiast self->do_write(length) lub jest inny powód?

+1

Jednym słowem: wygoda. – sehe

Odpowiedz

5

Bez przechwyconego obiektu nie można wywoływać metod klasy z poziomu lambda (na przykład do_write). Lub dostęp do zmiennych członków. Oczywiście, możesz zamiast tego napisać self->do_write(), ale jest to mniej eleganckie i potencjalnie wolniejsze (z powodu zaangażowanego shared_ptr).

+1

Aby rozszerzyć problem dotyczący prędkości: odpowiedzi z [to pytanie] (http://stackoverflow.com/questions/22295665/how-much-is-to-overhead-of-smart-pointers-compared-to-normal- pointers-in-c) wydają się wskazywać, że na starych/złych kompilatorach wyłuskiwanie inteligentnego wskaźnika może być wolniejsze niż dereferencja surowych wskaźników, ale nie powinno być prawie żadnych kar na współczesnych kompilatorach. – dshepherd

+0

@dshepherd: Wystarczająco sprawiedliwe, ale prawdopodobnie jest wolniejsze z wyłączonymi optymalizacjami (np. Tryb debugowania). –

+0

@shep I dunno: jest to wskaźnik const do łatwego do określenia obiektu. Współużytkowany ptr skonstruowany jest ze słabego ptr przechowywanego w obiekcie, zainicjowanym za pierwszym razem, gdy współdzielony ptr został utworzony z obiektu. Nie mogę sobie wyobrazić, że nie ma przypadków, w których optymalizator ma problemy z tym, nie wspominając o tym, że podzielony z tego może być zerowy! – Yakk

2

Podana odpowiedź brzmi: ABSOLUTNIE źle! Nie powinieneś przekazywać obu! Oto, jak należy to zrobić, na podstawie kodu, bez przechodzenia 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); 
     } 
     }); 
} 

I rzeczywiście, należy używać std::bind, nie lambdy dla tego produktu. Dzięki temu Twój kod stanie się bardziej zwarty.

+1

Odpowiedź Violet Giraffe wydaje mi się kompletna. Czy mógłbyś wyjaśnić, w jaki sposób to jest złe i dlaczego twoje jest lepsze? – Quentin

+0

@Quentin Cytując "Bez tego przechwyconego, nie można wywoływać metod klasy z wnętrza lambda". To jest całkowicie błędne. 'self' może zrobić dokładnie to, co robi' this'. Również błędem jest zakładać, że 'shared_from_this' jest wolniejsze (chociaż powiedział" potencjalnie ", co jest bezużyteczną, defensywną, płynną odpowiedzią). 'operator->' nie wykonuje żadnych testów, więc najmniejsza optymalizacja zabije różnicę w wydajności. Ta odpowiedź nie dostarcza żadnych użytecznych informacji, ale błędnych informacji opartych na założeniach i uogólnieniach. Przepraszam za bycie szorstkim, ale jestem zaskoczony. –

+0

Po przeczytaniu dokumentacji, nie powinno być żadnych implikacji związanych z efektami. Jednakże tracisz bezpośredni dostęp do elementu (tj. Nie ma 'tego->' ani 'self->'). – Quentin

Powiązane problemy