Czy lambdy c ++ 11 przechwytują zmienne, których nie używają?
124
Kiedy używam [=] aby wskazać, że chciałbym, aby wszystkie zmienne lokalne były przechwytywane przez wartość w lambdzie, czy spowoduje to wszystkie zmienne lokalne w kopiowanej funkcji, czy tylko wszystkie zmienne lokalne, które są używane przez lambdę ?
Przechwytywana jest każda zmienna wyraźnie wymieniona na liście przechwytywania. Domyślne przechwytywanie przechwytuje tylko zmienne, które (a) nie są wyraźnie nazwane na liście przechwytywania i (b) są używane w treści wyrażenia lambda. Jeśli zmienna nie jest wyraźnie nazwana i nie używasz tej zmiennej w wyrażeniu lambda, to zmienna nie jest przechwytywana. W twoim przykładzie my_huge_vectornie jest schwytany.
Per C ++ 11 §5.1.2 [wyr.prim.lambda] / 11:
Jeśli wyrażenie lambda ma skojarzone z nim ustawienie domyślne przechwytywania i jego instrukcja złożona odr-usesthis lub zmienna z automatycznym czasem przechowywania, a jednostka używana przez ODR nie jest jawnie przechwytywana, wówczas jednostka używana przez ODR jest przechwytywana niejawnie.
Twoje wyrażenie lambda ma skojarzone domyślne przechwytywanie: domyślnie przechwytujesz zmienne według wartości przy użyciu [=].
Jeśli i tylko wtedy, gdy używana jest zmienna (w rozumieniu reguły jednej definicji terminu „używana”), jest to zmienna przechwycona niejawnie. Ponieważ w ogóle nie używasz my_huge_vectorw treści („instrukcji złożonej”) wyrażenia lambda, nie jest ono przechwytywane niejawnie.
Aby przejść do §5.1.2 / 14
Jednostka jest przechwytywana przez kopię, jeśli
jest przechwytywany niejawnie, a domyślną wartością przechwytywania jest =lub jeśli
jest wyraźnie przechwycony za pomocą przechwycenia, które nie zawiera &.
Ponieważ twój my_huge_vectornie jest przechwytywany niejawnie i nie jest przechwytywany jawnie, nie jest w ogóle przechwytywany przez kopię ani przez odniesienie.
Powiem jednak, że całość § 5.1.2 jest ważna, aby zrozumieć wszystkie szczegóły. W tej sekcji zdefiniowano wiele terminów technicznych, a ponieważ definicje różnych składników wyrażeń lambda są z konieczności splątane, trudno jest wyciągnąć krótkie cudzysłowy, które ostatecznie mówią „to jest X i dlatego X”.
James McNellis
Pingowanie tutaj , aby zwrócić Twoją uwagę , co oznacza, że taka optymalizacja jest niedozwolona, przynajmniej w przypadku zmiennych nazwanych wprost. Nie jestem pewien, gdzie narysować granicę.
GManNickG
@GManNickG: To naprawdę niezły trolling ;-). Zajęło mi dobre trzy kliknięcia tego linku, zanim zdałem sobie sprawę, że faktycznie wskazuje na tę stronę ...: -O [W każdym razie ponownie przeczytam specyfikację językową, kiedy jutro rano wejdę do biura i zaktualizuję odpowiedź odpowiednio.]
James McNellis
O cholera, przepraszam !!! Odpowiedziano na moje pytanie, zamiast tego chciałem zamieścić tutaj link . To musiało być strasznie zagmatwane.
GManNickG
16
Nie, my_huge_vectornie zostanie schwytany. [=]oznacza, że wszystkie używane zmienne są przechwytywane w lambdzie.
Tak. Należy jednak pamiętać, że użyte jest słowem technicznym i tak naprawdę oznacza użytą regułę jednej definicji . Rozważmy więc na przykład void f() { const int size(10); [] { int x[size]; }; }. Tutaj sizenie jest przechwytywany, ale jest w porządku, ponieważ nie jest używany w sensie ODR. (Visual C ++ 2010 nie akceptuje tego kodu, albo z powodu zmiany specyfikacji po wydaniu VC10, albo z powodu błędu, prawdopodobnie zostanie to naprawione w przyszłej wersji; g ++ 4.5.1 akceptuje go.)
James McNellis
@JamesMcNellis dp nie martw się, MSVC to dziś wciąż kupa śmierdzących bzdur. por. godbolt.org/z/vHnnCX (sprawdź w gcc dla lulz). To mówi; Nie rozumiem, dlaczego jakikolwiek identyfikator pojawiający się w ocenianym wyrażeniu nie miałby być używany przez ODR. Myślę, że ten przypadek jest zdecydowanie używany przez ODR, chyba że masz na myśli, że można go zinterpretować jako constexpr, więc tylko wartość jest przydatna? Nie jestem pewien, czy kompilator zakłada const, że rzeczy nie ulegają mutacji. chyba że super agresywna flaga optymalizacji OX lub coś takiego.
Nie,
my_huge_vector
nie zostanie schwytany.[=]
oznacza, że wszystkie używane zmienne są przechwytywane w lambdzie.źródło
void f() { const int size(10); [] { int x[size]; }; }
. Tutajsize
nie jest przechwytywany, ale jest w porządku, ponieważ nie jest używany w sensie ODR. (Visual C ++ 2010 nie akceptuje tego kodu, albo z powodu zmiany specyfikacji po wydaniu VC10, albo z powodu błędu, prawdopodobnie zostanie to naprawione w przyszłej wersji; g ++ 4.5.1 akceptuje go.)const
, że rzeczy nie ulegają mutacji. chyba że super agresywna flaga optymalizacji OX lub coś takiego.