2016-05-09 19 views
8

Widziałem w wielu przykładach, które można wykorzystać pojedynczy znak, aby uchwycić wielu zmiennych jak następuje:Ile przechwytuje lambda w C++ 11?

Rect rect; 
Point point; 

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

    this->MemberFunction(); 
}; 

ten kończy się chwytając rect i point przez odniesienie i daje również dostęp do this, ale jak dużo to właściwie robi? Czy przechwytuje tylko te zmienne, których potrzebuje, czy też przechwytuje dosłownie wszystko, co jest w obecnym zakresie?

widziałem w innych przykładów, które można również określić poszczególne zmienne uchwycić tak:

Rect rect; 
Point point; 

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

    this->MemberFunction(); 
}; 

Czy istnieje Zaletą robi to w taki czy inny? Ktoś, z kim pracowałem, wspomniał kiedyś, że używanie wersji "przechwytuj wszystko" jest droższe, ale nie mogę znaleźć żadnej dokumentacji, która by to poparła. Po prostu chcę wiedzieć na pewno, więc nie robię kodu bardziej skomplikowanego, niż musi być, lub robię drogie rzeczy, których nie powinienem robić.

+0

Krótka odpowiedź: przechwytuje każdą zmienną, która jest używana * odr * w ramach lambda –

+2

Powinieneś tylko wymieniać poszczególnych członków, jeśli nie masz innej opcji z powodu konieczności użycia różnych metod przechwytywania dla niektórych z nich. Użycie '[&]' pozwala kompilatorowi określić, które zmienne są odr używane w oparciu o twój kod; mając na uwadze, że jeśli spróbujesz jawnie wymieniać wszystko, możesz wymienić niektóre niepotrzebne, generując nieefektywny kod. –

+0

@ M.M Z drugiej strony, z punktu widzenia bezpieczeństwa, określając, które zmienne * zamierzasz użyć w lambda, jawnie przechwytując _only_ tamte, istnieje mniejsze ryzyko, że następny programista lub nawet użytkownik nieumyślnie manipuluje przechwyconymi danymi. –

Odpowiedz

7

Według http://en.cppreference.com/w/cpp/language/lambda lista wychwytujący (części na placu szelki) wynosi:

lista oddzielony przecinkami zero lub większą liczbą wychwytów ewentualnie począwszy z chowu domyślnie. Lista przechwytywania może być przekazywana w następujący sposób [...]:

[a, & b] gdzie a jest przechwytywane przez wartość, a b jest przechwytywane przez odniesienie.

[to] oddaje to wskaźnik wartością

[&] przechwytuje wszystkie zmienne automatycznych ODR użyty w korpusie lambda przez odniesienie

[=] objąć wszystkie zmienne automatycznych ODR wykorzystywane w organizmie lambda wartością

[] rejestruje NIC

tę oznacza, że ​​przechwycone zostaną tylko zmienne automatyczne (zakres życia) używane w ciele lambda.

Nie widzę powodu, dla którego przechwytywanie wszystkiego przy pomocy [&] byłoby droższe niż pojedyncze przechwytywanie, ale jedną z zalet umieszczania przechwyconych artykułów jest to, że nie ma szans na uchwycenie czegoś, czego się nie spodziewałeś.

Z drugiej strony przechwytywanie za pomocą [=] może okazać się kosztowne, ponieważ spowoduje skopiowanie wszystkiego. Być może właśnie tak mówił twój współpracownik.

+0

Och, wow, nie wiem jak ja tęskniłem za tą stroną. Cały czas używam cppreference. Myślę, że masz rację w tym ostatnim punkcie. Właściwie nie wiedziałem, że możesz zrobić "[&]", aby uchwycić wszystko przez odniesienie, dopóki nie zobaczyłem go ostatnio w jakimś kodzie. Nie sądzę, aby którykolwiek z nas wiedział o tym, więc prawdopodobnie to właśnie "[=]" było sprawcą. Dzięki za wyczyszczenie tego. – Shenjoku

+0

"Nie ma szansy na uchwycenie czegoś, czego się nie spodziewałeś" _ jest ważne –

1

To kończy się chwytanie rect i punkt przez odniesienie, a także daje dostęp do tego, ale ile faktycznie przechwytuje?

przypadku robienia z [&] by objąć wszystkie zmienne w korpusie lambda, które mają automatyczny czas przechowywania i odr używanych.

Oto przykład:

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 
} 

Jeśli wiesz, że będziesz uchwycić tylko jedną zmienną, nie trzeba uchwycić wszystko przez wartość/odniesienia.

Z drugiej strony, jeśli wiesz, że będziesz przechwytywać kilka zmiennych, przechwytywanie ich za pomocą [&] lub [=] jest łatwiejsze niż wpisanie ich wszystkich.