Prenons l'exemple minimale suivante:std :: list et std :: for_each: où est ma fin?
#include <functional>
#include <algorithm>
#include <list>
int main() {
std::list<std::function<void()>> list;
list.push_back([&list](){ list.push_back([](){ throw; }); });
std::for_each(list.cbegin(), list.cend(), [](auto &&f) { f(); });
}
Il compile et lance une exception au moment de l'exécution. Je suppose que seul le premier lambda est exécuté par le std::for_each
, mais apparemment je me trompais: si j'ajoute un autre lambda à la fin de la liste, l'itération atteint aussi lambda.
Nous allons nous revenions l'exemple (push_front
au lieu de push_back
et crbegin
/crend
au lieu de cbegin
/cend
):
#include <functional>
#include <algorithm>
#include <list>
int main() {
std::list<std::function<void()>> list;
list.push_front([&list](){ list.push_front([](){ throw; }); });
std::for_each(list.crbegin(), list.crend(), [](auto &&f) { f(); });
}
En raison de l'exemple précédent, je me attendais à ce compiler et accident ainsi.
Au lieu de cela, il compile et ne plante pas. Cette fois, la fonction mise en avant de la liste n'est pas exécutée.
La question est assez simple: est-ce correct?
Pourquoi sont si contre-intuitifs les deux exemples?
Dans le premier cas, je m'attendais à quelque chose de différent et j'avais tort, ce n'est pas un problème.
Quoi qu'il en soit, j'aurais attendu une cohérence entre les deux boucles. Je veux dire, la deuxième fonction est exécutée dans un cas et elle n'est pas exécutée dans l'autre cas, mais je répète d'un commencer à un fin dans les deux cas.
Qu'est-ce qui ne va pas dans mon raisonnement?
compilateur utilisé? –
@GillBates GCC 6.1 et 3.9 fonctionnent comme décrit dans la question. Est-ce pertinent? Je ne pensais pas que cela pourrait être un problème du compilateur. – skypjack
Ne devrait-il pas ajouter en effet le lambda (premier exemple)? Les itérateurs ne sont pas invalidés comme dans le cas de 'std :: vector'. – vsoftco