2016-05-09 10 views
8

Ich habe in mehreren Beispielen zu sehen, dass Sie ein einzelnes Zeichen wie mehrere Variablen erfassen können die folgenden:Wie viel wird ein C++ 11-Lambda-Capture tatsächlich erfassen?

Rect rect; 
Point point; 

auto someLambda = [&](const SomeType& var) 
{ 
    if (rect.Contains(point)) 
    { 
     var.Something(); 
    } 

    this->MemberFunction(); 
}; 

Dies endet mit rect und point durch Verweis Grabbing und gibt auch Sie this zugreifen, aber wie viel fängt es tatsächlich ein? Erfasst es nur die Variablen, die es benötigt, oder erfasst es buchstäblich alles, was es im aktuellen Bereich gibt?

ich in anderen Beispielen gesehen haben, dass Sie auch einzelne Variablen zu erfassen, wie dies angeben:

Rect rect; 
Point point; 

auto someLambda = [this, &rect, &point](const SomeType& var) 
{ 
    if (rect.Contains(point)) 
    { 
     var.Something(); 
    } 

    this->MemberFunction(); 
}; 

Gibt es irgendeinen Vorteil zu tun es die eine oder die andere? Jemand, mit dem ich einmal gearbeitet habe, erwähnte einmal, dass die Verwendung der "capture all" Version [&] teurer ist, aber ich kann keine Dokumentation finden, die das unterstützt. Ich will nur sicher wissen, dass ich Code nicht komplexer mache, als es sein muss, oder teure Dinge tue, die ich nicht tun sollte.

+0

Kurze Antwort: es erfasst jede Variable, die * odr-used * innerhalb des Lambda –

+2

ist Sie sollten nur einzelne Mitglieder auflisten, wenn Sie keine andere Option haben, weil Sie für einige von ihnen verschiedene Capture-Methoden verwenden müssen. Mit '[&]' kann der Compiler herausfinden, welche Variablen basierend auf Ihrem Code verwendet werden. Wenn Sie jedoch versuchen, alles explizit aufzulisten, können Sie einige unnötige auflisten und ineffizienten Code generieren. –

+0

@ M.M Auf der anderen Seite besteht aus Sicherheitsgründen weniger die Gefahr, dass der nächste Entwickler oder Sie unbeabsichtigt manipulierte Daten manipulieren, indem Sie angeben, welche Variablen Sie * im Lambda verwenden wollen. –

Antwort

7

Nach http://en.cppreference.com/w/cpp/language/lambda die Aufnahmeliste (der Teil in eckigen Klammern) ist:

eine durch Kommata getrennte Liste von Null oder mehr Aufnahmen, die gegebenenfalls beginnend mit einem Einfang-default. Die Erfassungsliste kann wie folgt übergeben werden:

[a, & b] wobei a vom Wert erfasst wird und b durch Referenz erfasst wird.

[Dies] fängt die diesen Zeiger nach Wert

[&] erfasst alle automatischen Variablen ODR-verwendet im Körper des der Lambda durch Bezugnahme

[=] erfasst alle automatischen Variablen odr verwendet im Körper des Lambda-Wert von

[] fängt nichts

diese bedeutet, dass nur die im Körper des Lambda verwendeten automatischen (Scope-Lifetime) Variablen erfasst werden.

Ich kann nicht sehen, warum alles mit [&] erfassen würde teurer als einzelne Captures, aber ein Vorteil der Auflistung der Captures explizit ist, dass es keine Chance gibt, etwas zu erfassen, was Sie nicht erwartet haben.

Auf der anderen Seite könnte das Capturen mit [=] teuer erweisen, da es Kopien von allem macht. Vielleicht hat sich das auf Ihren Kollegen bezogen.

+0

Oh wow, ich weiß nicht wie ich diese Seite verpasst. Ich benutze cppreference die ganze Zeit. Ich denke, Sie haben Recht bei diesem letzten Punkt. Ich wusste wirklich nicht, dass du '[&]' machen kannst, um alles durch Verweis zu erfassen, bis ich es kürzlich in einem Code gesehen habe. Ich glaube nicht, dass einer von uns davon wusste, also war es wahrscheinlich der "Täter". Danke, dass du das geklärt hast. – Shenjoku

+0

Die _ "keine Chance, etwas einzufangen, das Sie nicht erwartet haben." _ Ist wichtig –

1

Dies endet damit, rect und Punkt per Referenz zu greifen und gibt Ihnen auch Zugriff darauf, aber wie viel erfasst es tatsächlich?

Wenn Sie mit [&] erfassen sie erfasst alle Variablen im Körper des Lambda, die automatische Speicherdauer und odr verwendet haben.Hier

ein Beispiel:

int main() 
{ 
    int num = 50; 
    [&] { std::cout << num << '\n'; }(); // num captured by reference 
    [=] { std::cout << num << '\n'; }(); // num captured by value 

    [&num] { std::cout << num << '\n'; }(); // by reference 
    [num] { std::cout << num << '\n'; }(); // by value 
} 

Wenn Sie wissen, dass Sie nur eine Variable erfassen wird, brauchen Sie nicht alles, was von Wert/Bezug zu erfassen.

Aber auf der anderen Seite, wenn Sie wissen, dass Sie ein paar Variablen erfassen werden, ist es einfacher, sie mit [&] oder [=] zu erfassen, als sie alle aufzuschreiben.

Verwandte Themen