Les lambdas C ++ 11 capturent-ils les variables qu'ils n'utilisent pas?

124

Lorsque j'utilise [=]pour indiquer que je voudrais que toutes les variables locales soient capturées par valeur dans un lambda, cela entraînera-t-il la copie de toutes les variables locales de la fonction ou simplement de toutes les variables locales utilisées par le lambda ?

Donc, par exemple, si j'ai:

vector<int> my_huge_vector(100000);
int my_measly_int;
some_function([=](int i){ return my_measly_int + i; });

Mon_huge_vector sera-t-il copié, même si je ne l'utilise pas dans le lambda?

HighCommander4
la source

Réponses:

115

Chaque variable expressément nommée dans la liste de capture est capturée. La capture par défaut ne capturera que les variables qui sont à la fois (a) non expressément nommées dans la liste de capture et (b) utilisées dans le corps de l'expression lambda. Si une variable n'est pas expressément nommée et que vous n'utilisez pas la variable dans l'expression lambda, la variable n'est pas capturée. Dans votre exemple, my_huge_vectorn'est pas capturé.

Selon C ++ 11 §5.1.2 [expr.prim.lambda] / 11:

Si une expression lambda a une capture par défaut associée et son instruction composée odr-uses this ou une variable avec une durée de stockage automatique et que l' entité utilisée par odr n'est pas explicitement capturée, alors l' entité utilisée par odr est dite implicitement capturée.

Votre expression lambda est associée à une capture par défaut: par défaut, vous capturez des variables par valeur à l'aide de [=].

Si et seulement si une variable est utilisée (dans le sens d'une règle de définition unique du terme «utilisé») est une variable capturée implicitement. Puisque vous n'utilisez pas my_huge_vectordu tout dans le corps (l '"instruction composée") de l'expression lambda, elle n'est pas capturée implicitement.

Pour continuer avec §5.1.2 / 14

Une entité est capturée par copie si

  • il est implicitement capturé et la capture par défaut est =ou si
  • il est explicitement capturé avec une capture qui n'inclut pas de fichier &.

Puisque votre my_huge_vectorn'est pas capturé implicitement et qu'il n'est pas explicitement capturé, il n'est pas du tout capturé, par copie ou par référence.

James McNellis
la source
10
Avez-vous une citation sainte?
GManNickG
Je dirai cependant que l'intégralité du §5.1.2 est importante pour comprendre tous les détails. Il y a beaucoup de termes techniques définis dans cette section et parce que les définitions des différents composants des expressions lambda sont nécessairement intriquées, il est difficile de sortir de courtes citations qui disent définitivement "c'est X et c'est pourquoi X".
James McNellis
Ping à votre attention ici , qui dit qu'une telle optimisation n'est pas autorisée, du moins pour les variables explicitement nommées. Je ne sais pas où tracer la ligne.
GManNickG
@GManNickG: C'est un très bon trolling ;-). Il m'a fallu trois bons clics sur ce lien avant de me rendre compte qu'il pointait réellement vers cette page ...: -O [Dans tous les cas, je relirai les spécifications de la langue quand j'arriverai au bureau demain matin et je mettrai à jour la réponse appropriée.]
James McNellis
Oh merde, désolé !!! Ma question a été répondue, je voulais plutôt créer un lien ici . Cela a dû être terriblement déroutant.
GManNickG
16

Non, my_huge_vectorne sera pas capturé. [=]signifie que toutes les variables utilisées sont capturées dans le lambda.

Thomas Minor
la source
6
Oui. Notez que utilisé est un mot technique, cependant, et signifie vraiment la règle d'une définition utilisée . Alors, par exemple, considérez void f() { const int size(10); [] { int x[size]; }; }. Ici, ce sizen'est pas capturé mais c'est correct car il n'est pas utilisé dans le sens ODR. (Visual C ++ 2010 n'accepte pas ce code, soit parce que la spécification a changé après la publication de VC10, soit en raison d'un bogue, cela sera vraisemblablement corrigé dans une prochaine version; g ++ 4.5.1 l'accepte.)
James McNellis
@JamesMcNellis ne vous inquiétez pas, MSVC est toujours un tas de merde puante aujourd'hui. cf. godbolt.org/z/vHnnCX (vérifiez dans gcc pour le lulz). Cela dit; Je ne comprends pas pourquoi un identifiant apparaissant dans une expression évaluée ne serait pas utilisé par ODR. Je pense que ce cas est définitivement utilisé par ODR à moins que vous ne vouliez dire qu'il pourrait être interprété comme une constexpr, donc seule la valeur est utile? Je ne suis pas sûr que le compilateur suppose que les constchoses ne mutent pas potentiellement. sauf peut-être un drapeau d'optimisation super agressif OX ou des trucs.
v.oddou