2017-05-17 3 views
5

Aujourd'hui, j'ai rencontré un comportement très peu intuitif (pour moi, au moins) en C++ 11 lambdas. Le code en question est le suivant:Retour d'un lambda capturant une variable locale

Au lieu d'imprimer 5, ceci imprime du charabia. En fait, au moins dans ma version de GCC, si j'active l'indicateur d'optimisation -O2, il imprime en réalité 5. Puisque la sortie dépend du niveau d'optimisation du compilateur, c'est un comportement indéfini. Après un moment, je pense avoir compris ce qui se passe. Quand la fonction sum est appelée, une variable de pile correspondant à l'argument x est mise à 2, alors la fonction sum retourne, et cette variable de pile peut être écrasée par tout ce que le compilateur doit mettre là pour exécuter le code suivant et au moment où le lambda est finalement exécuté, l'endroit où x ne contient plus 2, et le programme ajoute 3 à un entier arbitraire.

Existe-t-il un moyen élégant de faire en C++ en garantissant que la variable est capturée correctement?

+4

Capture par valeur '[=]'. – Galik

+0

Merci! C'était beaucoup plus simple que ce à quoi je m'attendais. –

+2

Juste pour le lecteur, c'est C++ 14, pas C++ 11. La déduction de type des valeurs de retour de la fonction a été ajoutée en C++ 14. – cdhowie

Répondre

8

int x a une durée de vie limitée. Les références aux variables de stockage automatique (ce que vous appelez "la pile") ne sont valables que pendant la durée de vie de la variable. Dans ce cas, seulement jusqu'à la fin du cadre de la pile (la portée) où la variable existe, ou la fonction pour les arguments de la fonction.

[&] capture toute variable mentionnée ("locale") par référence, sauf this (qui est capturée par la valeur si elle est utilisée ou implicitement utilisée). [=] capture toute variable mentionnée par valeur. [x] capturerait x explicitement, et [&x] par référence explicitement. En C++ 17, [*this] fonctionne également. Il existe également [x=std::move(x)] ou [blah=expression].

En général, si le lambda survit à la portée actuelle n'utilisez pas [&]: soyez explicite sur ce que vous capturez.

+0

Merci pour la réponse élaborée. La plupart des réponses que j'ai cherchées impliquant Cying sur C++ avaient beaucoup de code de modèle que je ne pouvais pas comprendre, donc j'ai juste commencé à essayer des trucs.Maintenant, je sais mieux ce que je fais. –