Ce post contient un exemple de ce qu'il ne faut jamais faire.
Bonjour tout le monde !
J'ai récemment dû "corrigé" le code d'une personne débutant en programmation. Le but de l'exercice était le maniement des chaînes mais ce n'est pas ce qui nous intéresse ici. A la fin de cet exercice se trouvait la traditionnelle question qui proposait de demander à l'utilisateur à la fin de l'exécution si il désirait recommencer l'exécution du programme.
Or cette personne venait de suivre un cours sur la récursion et à proposer la solution suivante:
Passé la surprise, j'ai testé son code qui, à ma grande surprise, fonctionne sans problème. Il était cependant évident que ce n'était pas ce que l'auteur de la question attendait.
La question que je me pose est donc la suivante:
Pour quel raison ne doit pas utiliser un main récursif du moment que c'est fait correctement et qu'il existe une porte de sortie ? (Tout en précisant que je sais pertinemment que l'utilisation de la récursion dans l'exemple que j'ai présenté est une mauvaise utilisation du concept.)
Que dire de plus à cette personne à part qu'on utilise pas la récursion pour ça ?
pour un petit programme, ça va, mais lorsque tu lance un gros programme, ça veux dire recharger tous depuis le début!
Ce peut faire gros!
En plus, si tu utilise un singleton, le fait d'essayer de recréer un objet échouera.
De plus, main() est le coeur même du programme, lancer une deuxième fois cette fonction est, bien que possible, une abération qui va à l'encontre même de la programmation.
En plus, si tu utilise un singleton, le fait d'essayer de recréer un objet échouera.
Les singleton sont créés avant l'appel à la fonction main. Cela ne pose pas de problème.
Citation : Geoffroy
pour un petit programme, ça va, mais lorsque tu lance un gros programme, ça veux dire recharger tous depuis le début!
Ce peut faire gros!
C'est aussi ce que je lui ais dit. Il m'a répondu que c'était le principe même de la récursion (ce qui est vrai).
Citation : Geoffroy
De plus, main() est le coeur même du programme, lancer une deuxième fois cette fonction est, bien que possible, une abération qui va à l'encontre même de la programmation.
Tout à fait d'accord, mais pourquoi ?
En fait j'aurais dû préciser en proposant un exemple ou l'utilisation de la récursion est justifié et pas un exemple ou l'idée même de récursion est fausse.
C'est aussi ce que je lui ais dit. Il m'a répondu que c'était le principe même de la récursion (ce qui est vrai).
C'est le principe, mais comme tous les principes, ils ne sont pas bon partout.
J'aimerai bien voir une telle méthode dans un programme tel qu'un photoshop, ou un autre gros programme du genre!
En plus, il suffit d'un petit crack path pour surcharger complètement l'ordinateur très facilement!
Pour le dernier truc, c'est le COEUR du programme, et le comble d'un coeur, ce serai bien de ne pas être unique, car il perdrai son sens!
De plus, je me demande ce qui arrive lorsque l'on reinitialise des libs ou des fenêtre comme Win32 Qt SDL ou SFML... Disons que je doute que ça soit propre...
les libs ne sont pas réinitialisé, seulement la fonctions.
Mais c'est vrai que dans le cas d'une musique de fond pour le programme, si tu relance main(), elle doit également se lancer une deuxième fois.
Je vous dit pas ce queça doit donner lorsqu'on fait ça plein de fois!
S'il n'y a pas des inits/libérations applicatives comme ici, cela ne devrait poser aucun problème.
J'ai souvenir de codes du OCCC qui utilisaient ce genre de construction.
Potentiellement attention s'il y a des variables locales trop conséquentes dans la fonction. A un moment indéterminé il pourra saturer sa pile.
Son principal problème, ici, viendra qu'il va partir en boucle infinie et saturer sa pile s'il rentre autre chose qu'un nombre. Mais cela sera vrai avec toute récursion -- que dis-je? boucle!--, testant mal la condition d'arrêt comme ici (correct -> FAQ C++ de developpez -> #cin_verify). Le côté appel de main() me parrait plutôt anecdotique.
Recursion pour un algo de calcul (ou autre) oui.
Récursion pour continuer d'interagir, non : cela introduit implicitement un nombre d'interactions max qui est difficilement quantifiable, d'autant qu'il variera selon les opérations réalisées derrière.
Citation : Nanoc
Citation : Geoffroy
En plus, si tu utilises un singleton, le fait d'essayer de recréer un objet échouera.
Les singleton sont créés avant l'appel à la fonction main. Cela ne pose pas de problème.
Cela dépend. Tous les singletons ne s'initialisent pas paresseusement sans argument.
PS: interdire n'est pas dans la philosophie du C ni du C++ -- contrairement à d'autres langages.
Potentiellement attention s'il y a des variables locales trop conséquentes dans la fonction. A un moment indéterminé il pourra saturer sa pile.
C'est sûr, mais c'est le principal problème de la récursion.
Citation : lmghs
Son principal problème, ici, viendra qu'il va partir en boucle infinie et saturer sa pile s'il rentre autre chose qu'un nombre. Mais cela sera vrai avec toute récursion -- que dis-je? boucle!--, testant mal la condition d'arrêt comme ici (correct -> FAQ C++ de developpez -> #cin_verify).
Oui, oui mais j'ai simplifié le code proposé afin de ne montrer que la partie utile pour la question qui m'intéressait.
Citation : lmghs
Recursion pour un algo de calcul (ou autre) oui.
Récursion pour continuer d'interagir, non : cela introduit implicitement un nombre d'interactions max qui est difficilement quantifiable, d'autant qu'il variera selon les opérations réalisées derrière.
C'est donc plutôt cela. On a affaire ici à une mauvaise utilisation de la récursion. Cependant dans le cas présent, si l'on crée un bloc autour de la partie principale du programme (que je n'ai pas mise ici), on ne construit qu'un int à chaque appel ce qui veut dire qu'on peut potentiellement faire quelques millions d'appel récursifs à la fonction main() avant de saturer la pile.
Citation : lmghs
J'ai souvenir de codes du OCCC qui utilisaient ce genre de construction.
Qu'est-ce que le OCCC ? Okhlahoma city Community college ? (Je pense pas mais j'ai rien trouvé d'autre)
Citation : lmghs
interdire n'est pas dans la philosophie du C ni du C++ -- contrairement à d'autres langages.
C'est vrai. Mais alors aurais-tu un exemple où ce genre de construction a une utilité ? (OCCC ?)
Je pense, mais je ne suis pas sûr, que de relancer le main, c'est équivalent à relancer le programme (pas de le recharger en mémoir, juste le relancer) ce qui n'est pas corrècte, pour relancer un programme, il faut d'abord qu'il se termine, et le compilo laisse passer ce truc, car main est une fonction comme toutes autres, sauf qu'elle est spéciale (c'est la première à etre appeler, et la dernière à être libérer, un appel = une libération), en cas de récursion plusieurs appelles, une libération, c'est pas normal, et ce n'est pas dutout corrècte! enfin, de mon point de vue.
La maîtrise des fondamentaux est le fondamental de la Maîtrise.
Moi le truc pour l'instant qui pour moi empêcherait d'utiliser main sous forme récursive, c'est que son prototype est imposé...
C'est vrai qu'on peut pas en faire grand chose. Mais bon si on code un main récursif, on peut bien coder des variables à coté pour s'affranchir de ce problème.
La fonction main est appelée par le système d'exploitation, elle ne peut pas être appelée par le programme, c'est-à-dire qu'elle ne peut pas être récursive.
apres je sais pas pourquoi le compilateur le permet et qu'à l'execution ca marche
On a donc défini une qui sera appelée à un certain moment donné qui sera "l'entrée" du programme. Cette fonction est une parmi celles qui créer les variables globales et les détruits. Vous me direz : mais une variable automatique n'as pas besoin de fonction pour être créée elle existe au moment de ça déclaration et à la fin du bloc : erreur. Le compilateur s'occupe de transformer une déclaration de variables et d'une fin de bloc par un "push" en mémoire et un "pop". Cela a été programmé quelque part!
main c'est une fonction, un sous-programme, normal qui n'as aucune spécialité autre que d'être une surcharge d'une fonction définie dans le CRT!
Donc message à ceux qui font du C++ en passant d'être 100% libre de faire ce qu'ils veulent. Plus qu'en C#, en Java ou en PHP et bien : non!
Au temps pour moi, le vrai sigle, c'est (www.) IOCCC (.org) -> The International Obfuscated C Code Contest.
Et effectivement, si vous vérifiez le prochain brouillon du standard (-> n2135) §3.6.1/3 : "The function main shall not be used (3.2) within a program.", faut pas appeler main.
(NB: Je pêche à voir le rapport à l'ODR (§3.2) ; -> fclc++ pour le décryptage)
main est juste une fonction, donc on peut faire un main récurcif, c'est moche, ca fait hurler mais ca marche.
Le bug est dans la notion de porte de sortie, en effet si je lance 3 fois mon programme, j'aurais dans la pile d'exécution
main( main(main ()))
en gros je vais empiler des mains a chaque exécution, ce qui va surcharger la pile.
La sortie s'effectue en fait lorsqu'on décide de quitter le dernier main lancé, alors la on dépile tout le monde.
En pratique, avec une entrée utilisateur faudrait vraiment un frénétique pour remplir la pile et planter l'ordi, donc ca va marcher, mais c'est juste moche.
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
La maîtrise des fondamentaux est le fondamental de la Maîtrise.
La maîtrise des fondamentaux est le fondamental de la Maîtrise.
* Un wrapper C++ pour sqlite * Une alternative a boost units