Bonjour est ce que goto est propre a c++ ou non ?
Version imprimable
Bonjour est ce que goto est propre a c++ ou non ?
Salut,
Le mot clé goto a été hérité du C, et son usage est fortement déconseillé. En C++, il y a toujours moyen de s'en passer.
Meilleures salutations
Thierry
non, bien au contraire. C'est un héritage de la programmation procedurale de l époque.
Y'a quand même UN cas de figure en C/C++ où le goto est intéressant: une sorte de 'break' pour sortir de multiples boucles.
Certes des alternatives existent, mais c'est plus lent...
Exemple: rechercher un élément dans une matrice
La preuve que c'est vraiment utile: la syntaxe du Java autorise au 'break' de sortir d'une boucle multipleCode:
1
2
3
4
5 for (int i=0; i<M; ++i) for (int j=0; j<N; ++j) if (A[N*i+j]==a) goto found; found:;
Bof, je préfère, de loin :Citation:
Envoyé par Charlemagne
Code:
1
2
3
4
5
6
7 int find(T A[], int N, int M, T a) { for(int i = 0; i < M; ++i) for(int j = 0; j < N; ++j) if (A[N*i + j] == a) return N*i + j; return -1; }
Pareil.
Bof. A moins d'être en temps réel, je ne vois vraiment pas l'intérêt de se passer de constructions plus propres.Citation:
Certes des alternatives existent, mais c'est plus lent...
Le principe utilise dans cette preuve me laisse un peu songeur...Citation:
Envoyé par Charlemagne
Moi aussi, je préfère un return, mais c'était un exemple à la con...Citation:
Envoyé par Sylvain Togni
Citation:
Bof. A moins d'être en temps réel, je ne vois vraiment pas l'intérêt de se passer de constructions plus propres.
Arrêtez de me critiquer, ou bien critiquez donc également Stroustrup.Citation:
Le principe utilise dans cette preuve me laisse un peu songeur...
Je le cite de son bouquin, sur le paragraphe consacré au 'goto':
Déjà lu un bouquin de C?Citation:
(...) Un goto peut également être important dans les cas rares pour lesquels une efficacité optimale est indispensable (...)
L'une des applications les plus judicieuses de cette instruction consiste à sortir d'une boucle imbriquée ou d'une instruction switch (un break ne permet de remonter qu'un seul niveau de boucle ou d'instruction switch). Par exemple (...)
Stroustrup cite Java?
Plus sérieusement, l'usage de goto pour cette tâche se défend même si je ne partage pas cet opinion.
Thierry
:calin:Citation:
Envoyé par Charlemagne
Ca va mieux maintenant?
Il n'ecrit rien de semblable aCitation:
ou bien critiquez donc également Stroustrup.
Je le cite de son bouquin, sur le paragraphe consacré au 'goto':
Raisonnement que je continue a trouver tres douteux, quelle que soit mon opinion sur les goto et la possibilite de sortir de plusieurs boucles en meme temps.Citation:
Envoyé par Charlemagne
Tu as deja lu mes messages sur le forum C?Citation:
Déjà lu un bouquin de C?
Voici le lien vers un débat au sujet de l'instruction goto qui a eu lieu sur le forum C: http://www.developpez.net/forums/showthread.php?t=75764
Thierry
Eternelle polémique.Citation:
Envoyé par Maria1505
Je suggérrais de s'initier à l'assembleur x86....
même si il n'y a aucun goto dans ton code source en C++ eh bien ton programme une fois compilé cela donnera toujours des jmp,je etc...
Les sauts ne sont ni plus ni moins que des goto en ASM.
Ceci dit il faut éviter d'utiliser goto c'est certain
exemple en C
int a=16;
if (a==20) FaireQQueChose()
En ASM cela va donner
mov ax,10h
cmp ax,10h
je adresse_FaireQQueChose
donc en langage machine cela donnera un goto ...
;)
goto pose pas des problèmes évidents face au RAII ?
Je ne vois rien. A moins que tu parles des limitations sur les cibles des goto en C++ qui font qu'on ne peut pas sauter un constructeur?Citation:
Envoyé par loufoque
J'avoue avoir très peu utilisé goto en C++, je ne sais donc pas quelles en sont les restrictions.
Je pensais que c'était comme en C. (Mais bon, en C non plus je connais pas parfaitement)
C'est moche et ça n'est pas beaucoup plus rapide que d'utiliser une condition de sortie de boucle:Citation:
Envoyé par Charlemagne
Ensuite si tu tiens vraiment à optimiser ce type de chose, commence par utiliser une boucle simple plutôt qu'une double boucleCode:
1
2
3
4
5
6
7
8
9
10 bool found = false; for (int i=0; (i<M) && (!found); ++i) { for (int j=0; j<N; ++j) { if (A[N*i+j]==a) found = true; } }
Maintenant, si tu possèdes la STL c'est tout aussi performant et plus lisible d'utiliserCode:
1
2
3
4
5
6 for (int i=0; (i < M*N) && (!found); ++i) { if (A[N*i+j]==a) found = true; }
Code:
1
2 find(A, A+(M*N), a);
C'est un peu plus long en temps de calcul à ta manière,Citation:
Envoyé par Jan Rendek
et franchement je trouve le goto plus élégant.
C'est hors de propos: Tu peux effectivement ici ne faire qu'une boucle, mais c'était un exemple à la con pour illustrer une boucle imbriquée... rien de plus.Citation:
Envoyé par Jan Rendek
Dans ce cas d'une boucle simple, t'aurais dû plutôt utiliser un 'break'.
Tu peux toujours faire part de tes remarques à Stroustrup... que visiblement tu prends également pour un imbécile.
Jan Rendek, si le goto est completement futile, pourquoi bigre fait-il parti du langage, nom de dieu !?
et derniere petite remarque, car bcp de choses ont déja été dites ; en assembleur, le "goto" est indispensable, car toutes les boucles fonctionnent avec ca !
voila, de mon avis perso, c'est pas propre du tout a utiliser, et c'est meme a proscrire, mais ne sois pas faschiste, il existe des cas ou l'on cherche l'optimisation et les performances, et il devient tres utile.
je rapelle que pour programmer haut niveau, il existe des langages meilleurs que le C/C++, mais que ceux ci en revanche ont une place manifeste dans les langages bas niveau et dans l'informatique industrielle.
Encore un argument que je ne comprend pas. Pourquoi auto fait-il partie du langage?Citation:
Envoyé par toxcct
pour faire parler les cons ? 8-)Citation:
Envoyé par Jean-Marc.Bourguet
serieusement, il est la parce que le standard ne dit pas comment l'exécution doit allouer une variable par défaut, et si un compilo veut mettre une variable dans le registre, rien ne lui empechera, sauf si on explicite "auto"
ps: que je ne fasse pas jeter de pierres, je ne parlais pas pour toi JM :aie:
A ma connaissance, il n'a pas cet effet la. Il n'est meme pas comme register (quelque chose devenu inutile qui ne l'a pas toujours ete) une suggestion au compilateur.Citation:
Envoyé par toxcct
Je ne l'ai pas pris pour moi. Je ne crois pas avoir donne ici mon opinion sur le goto.Citation:
que je ne fasse pas jeter de pierres, je ne parlais pas pour toi JM
pure spéculation votre honneur! Je ne pense pas que tout le monde ici soit d'accord.Citation:
je rapelle que pour programmer haut niveau, il existe des langages meilleurs que le C/C++, mais que ceux ci en revanche ont une place manifeste dans les langages bas niveau et dans l'informatique industrielle.
oh merde, faute de frappe !!!!Citation:
Envoyé par nikko34
je voulait dire qu'il y a mieux que le C/C++ pour le haut niveau et l'info de gestion, quand que C/C++ garde une place prépondérante en info indus !
Le goto est un atavisme de l'assembleur, il n'a quasiment plus sa place en C et encore moins en C++. Son utilisation pour sortir d'une boucle est complètement marginale. Je ne l'utiliserais que si cette boucle est un goulet d'étranglement. De plus, avant de la mettre en pratique j'aimerais voir les benchmarks avec et sans et évaluer le gain que cela représente.
Algorithmiquement les deux méthodes suivantes font exactement le même nombre de comparaisons. La seconde faisant une N*M affectations supplémentaire dans une variable que le compilateur assignera probablement dans un registre.
De toute les manières ce n'est pas une pratique à encourager à quelqu'un qui commence le C ou le C++. Cette solution brise le flot d'exécution normal, masque le véritable algorithme et induit des risques d'erreurs de maintenance.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13 bool found = false; for (int i=0; (i<M) && (!found); ++i) { for (int j=0; j<N; ++j) { found = (A[N*i+j]==a); } } ---------------------- for (int i=0; i<M; ++i) for (int j=0; j<N; ++j) if (A[N*i+j]==a) goto found; }
Si j'ai 10 boucles de ce genres, je dois fixer à la main 10 labels différents (found1, found2, found3...), que se passe-t-il quand je fais du 'refactoring' et que je déplace une boucle d'une autre unité de compilation ? Ou bien que j'intervertisse quelques lignes de code aux environs de l'étiquettes ?
Déjà il y a 20 ans, il y avait des tonnes de mise en garde contre le 'goto' en basique. On préconisait de le bannir au profit des 'gosub'. Ce n'est sûrement pas pour le réintroduire maintenant.
En assembleur le goto est indispensable, très bien. Justement son emploi principal est de mettre en oeuvre des boucles et des appels de routines. Si je programme en C c'est justement pour me faciliter le travail et ne pas gérer ces problèmes de sauts conditionnels et d'étiquettes. 'goto' je ne l'ai employé que quand je programmais des drivers, dans du C qui contenait allègrement 60% d'assembleur. Sûrement pas pour faire des boucles imbriquées.
Ensuite, je ne prend pas Stroustrupt pour un imbécile. Cependant, je me méfie des exemples et des citations extraites de leur contexte. Je doute profondémment que Stroustrupt milite pour l'usage systématique des 'goto' pour sortir d'une boucle multiple.
Bref, cette solution n'est en aucun cas plus élégante, ni efficace. Je crois que son seul mérite c'est de faire l33t HaXXor, mais ce n'est en aucun cas à employer dans du développement sérieux.
@toxcct: Si j'interviens dans ces forums c'est dans un but purement altruiste. J'accepte toute critique, mais sûrement pas de me faire traiter de 'fachiste' par quelqu'un que je ne connais ni d'Eve ni d'Adam.
Un argument en faveur du goto, c'est que ca fait deux fois que tu te plantes en essayant de montrer un code equivalent. Au moins, la premiere fois, le probleme etait moins grave, ici, tu n'as meme pas un bon resultat.Citation:
Envoyé par Jan Rendek
tu prend ma phrase hors contexte, et je ne parle surement pas de politique ici. "faschiste", c'etait pour dire que tu as une facon de pensée a mon avis tres "droite", que tu ne t'en écarte jamais, et limite que tu n'accepte pas les remarques et critiques. voila le seul sens dans lequel j'ai dit ce mot.Citation:
Envoyé par Jan Rendek
Je te retourne le compliment. Mon propos s'adresse uniquement à l'égard de ça:
Et non pas de l'ablation pure et simple de 'goto', ni de l'info indus ou que sais-je encore.Code:
1
2 Y'a quand même UN cas de figure en C/C++ où le goto est intéressant: une sorte de 'break' pour sortir de multiples boucles. Certes des alternatives existent, mais c'est plus lent...
Bien vu!! Je prenais même pas la peine de décortiquer son algo...Citation:
Envoyé par Jean-Marc.Bourguet
Voici une jolie preuve de l'utilité du goto...
Stroustrup l'exprimait mieux que moi, je te le recite:Citation:
Envoyé par Jan Rendek
Citation:
Il existe peu d'applications pour goto en programmation générale de haut niveau. Cette instruction peut en revanche se révéler très pratique lorsque le code C++ est généré par un programme plutôt qu'écrit directement par un programmeur. il est possible de voir des goto, par exemple, dans un analyseur syntaxique généré à partir d'une grammaire depuis un générateur d'analyseur [NDL Bison]. Un goto peut également être important dans les cas rares pour lesquels une efficacité optimale est indispensable (dans la boucle intérier d'une application temps réel, par exemple)
L'une des applications les plus judicieuses de cette instruction consiste à sortir d'une boucle imbriquée ou d'une instruction switch (un break ne permet de remonter qu'un seul niveau de boucle ou d'instruction switch). Par exemple:
Code:
1
2
3
4
5
6
7
8
9
10
11
12 void f() { int i; int j; for (i=0; i<n; ++i) for (j=0; j<m; ++j) if (nm[i][j]==a) goto found; // introuvable //... found: //nm[i][j]==a }
Je ne vois pas en quoi cela contredit mon propos.
Pour le coup, je suis curieux du gain en rapidité. Je vais tester ça, je posterais les résultats ici.Citation:
Son utilisation pour sortir d'une boucle est complètement marginale. Je ne l'utiliserais que si cette boucle est un goulet d'étranglement. De plus, avant de la mettre en pratique j'aimerais voir les benchmarks avec et sans et évaluer le gain que cela représente.
Salut,
L'instruction goto est, sans doute, l'une des instructions qui se retrouvent dans le plus grand nombre de langages de programmation, et pour cause: c'est une des réminiscence importante du langage machine/assembleur.
Il faut bien etre conscient que toutes les possiblités offertes par la programmation structurée et orientée objet ne sont, en définitive, que des goto "déguisés" - qu'il s'agisse des tests, des boucles, de la gestion d'erreur ou des phénomènes d'héritage/de polymorphisme...
Alors, évidemment, goto n'est absolument pas propre au C++, ce qui était quand meme, semble-t-il, le but du sujet ;)
Par contre, oui, goto existe en C++, et dans la plupart des langages de programmation d'ailleurs, mais, non, ce n'est absolument pas une raison pour l'utiliser.
Sans atteindre l'extrémisme de certains profs qui iront jusqu'à vous menacer de vous jeter par la fenetre si vous osez utiliser goto dans un programme, il faut malgré tout etre conscient que dans la très grosse majorité des cas, son utilisation peut etre évitée, au besoin, en modifiant l'algorithme qui nous incite à l'utiliser...
La beauté de la programmation structurée est qu'elle permet la "factorisation" d'un bloc d'instructions, voire, de décider à n'importe quel moment de déplacer ce bloc d'instructions pour une raison ou une autre.
De plus, la programmation structrée offre l'énorme avantage de présenter le code source sous une forme identique à ce que l'on a l'habitude de lire: un livre ou un journal, que l'on lit de "haut en bas" et "de gauche à droite".
Le goto présente quant à lui l'énorme inconvéniant de "casser" l'ordre logique de lecture d'une programmation structurée, principalement quand on se trouve face à une accumulation de goto ou face à des goto "montants".
La conséquence quasi inévitable est que la lecture du code devient beaucoup plus compliquée, ce qui entraine une perte de temps énorme, et sans commune mesure avec le gain de temps (dont j'attendrai la preuve qu'il est réel) occasionné par les goto lorsqu'il s'agit de modifier le code...
Parce qu'il s'agit d'une réminisence des langages datant d'avant les langages de troisième génération, et que certains "vieux" programmeurs n'ont connu que cette manière pour travailler...Citation:
Envoyé par toxcct
Mais personnellement, je n'aurais absolument rien contre un langage qui ne disposerait meme pas de cette instruction qui, bien pis que d'être futile, présente d'énormes inconvéniants et est dans la grosse majorité des cas remplacable par quelque chose qui permettra de rendre le code plus compréhensible ;)
Donc la, tu prends Stroustrup pour un vieux qui n'a pas sufaire la part des choses ? je suis d'accord avec tout ton discours, sauf ici !Citation:
Envoyé par koala01
Soustrup commence par:
"C++ possesses the infamous goto"
ensuite:
en anglais c'est "one of the few sensible uses of goto in ordinary code", c'est à dire que des applications judicieuses (littéralement, "sensées") dans le code de tous les jours, il y en a pas beaucoup.Citation:
L'une des applications les plus judicieuses de cette instruction consiste à sortir d'une boucle imbriquée ou d'une instruction switch (un break ne permet de remonter qu'un seul niveau de boucle ou d'instruction switch).
Sinon, dans le reste de son bouquin, il ne l'utilise pas. Ca doit vouloir dire quelque chose.
merci pr la traduction.Citation:
Envoyé par nikko34
je disais juste, en tout conscience de cette citation, que malgré tout la sympathie qu'il a pour le goto, il l'a quand meme incorporé au C++, ce qui est un signe malgré tout du minimum d'interet qu'on devrait avoir a son égard.
le probleme ne vient pas du goto mais de la mauvaise utilisation que des boulets en font, c'est pas plus compliqué que ca
Le C++ a hérité le goto du C.Citation:
Envoyé par toxcct
minimum est le mot.Citation:
ce qui est un signe malgré tout du minimum d'interet qu'on devrait avoir a son égard.
Tu peux expliquer comment tu reconnais une bonne utilisation d'un goto d'une mauvaise?Citation:
le probleme ne vient pas du goto mais de la mauvaise utilisation que des boulets en font, c'est pas plus compliqué que ca
Relis la discussion...Citation:
Envoyé par Jean-Marc.Bourguet
Quel message dans la discussion donne un critère effectif pour savoir si un goto est un "bon" goto ou un "mauvais"?Citation:
Envoyé par toxcct
Meme les meilleurs peuvent avoir leurs moments d'égarement ;)Citation:
Envoyé par toxcct
Et tu tires malgré tout des conclusions un peu hâtives suite à une mauvaise interprétation de mes écrits...
Ce que je voulais dire, c'est qu'il y a d'anciens codes (pas *forcément* en C++) pour lesquels les goto sont mangés à toutes les sauces...
Ne riez pas: je connais quelqu'un qui a rencontré un code composé de ... 20 goto sur... meme pas une centaine de lignes :P
Quand on en arrive à ce point, c'est que, visiblement, il y a un malaise quelque part, non :question:
En sommes, il s'agit surtout de l'expression de la mise en oeuvre d'une méthode d'algorithmie particulièrement inadaptée au langage de troisième génération (le flowchart, pour ne pas le nommer) qui devrait n'être réservé que dans le cadre d'une programmation en assembleur ou en langage machine...
Dans quelques cas extrèmement rares et très précis, on *peut* concevoir que le goto soit une alternative valable, mais, à ce jour, j'ai toujours su faire sans...
Un exemple parmis tant d'autres, en C, dans lequel l'utilisation du goto *peut* sembler adaptée:
Et, pourtant, un algorithme très légèrement différent permettra de s'en passer:Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 int** mafonct(int n1,int n2) { int** temp; int i; int j; temp=malloc(sizeof(int*)*n1); if(temp==NULL) goto Err1; for(i=0;i<n1;i++) { temp[i]=malloc(sizeof(int)*n2); if(temp[i]==NULL) goto Err2; } return temp; Err2: for(j=0;j<i;j++) free(temp[j]); Err1: free(temp); return NULL; };
Les deux codes sont exactement équivalents: il alloue tous les deux la mémoire pour une matrice d'entier de n1 lignes et de n2 colones...Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 int** fonct2(int n1,int n2) { int errcode=0; int i; int j; int** temp; temp=malloc(sizeof(int*)*n1); if(temp==NULL) errcode=1; else { while(errcode==0 && i<n1) { temp[i]=malloc(sizeof(int)*n2); if(temp[i]==NULL) errcode=2; else i++; } } switch(errcode) { case 2: for(j=0;j<i;j++) free(temp[i]); case 1: free(temp); temp=NULL; break; } return temp; }
La seule chose, c'est que le premier brise l'ordre logique d'exécution, alors que le second la respecte entièrement...
Je ne considère nullement Stroutrup comme un "vieil imbécile qui n'a pas su faire la part des choses" parce qu'il a inclu l'instruction goto dans son langage: son but premier était de créer un langage qui dépayserait le moins possible les codeurs habitués au C, et il est donc logique (quoi qu'on puisse estimer que c'est un mauvais service rendu) qu'il ai fourni une instruction qui, elle, est utilisée principalement par de vieux imbéciles qui ne font pas la part des choses ;)
Il a d'ailleurs si bien fait la part des choses qu'il ne l'utilise dans son bouquin que.. quand il parle de l'instruciton ;)
Heuu... comprenons nous bien (sinon, bientot, on m'accusera de considérer linus tovald comme un vieil imbécile :P) je retire du lot tous ceux qui, en connaissance de cause, utilisent le goto dans la très rare portion des fois où il s'avère nécessaire ;)
Parfois, mais ca représente vraiment une partie infinitésimale des cas où le goto pourrait sembler intéressant, il apparait qu'il est définitivement la meilleure solution à un problème donné... et, dans ce cas, nécessité fait loi, il reste donc logique de l'utiliser...
Même en assembleur on peut programmer de manière structurée.Citation:
Envoyé par koala01
On peut toujours faire sans, c'est démontré quelque part. Au pire:Citation:
Dans quelques cas extrèmement rares et très précis, on *peut* concevoir que le goto soit une alternative valable, mais, à ce jour, j'ai toujours su faire sans...
Et même si le goto n'est plus là, le problème lui est resté.Code:
1
2
3
4
5
6
7
8 state = 1; switch(state) { case 1: ...; state++; break; case 2: state = 6; break; ... }
Qu'est-ce que je disais... on transforme un état implicite donné par la position en un état explicite donné par une variable sans rien changé au déroulement du programme. Les deux versions ont exactement les mêmes défauts. Le problème fondamental du goto, c'est un problème de difficulté à raisonner sur les programmes qui l'emploient. Et jouer avec des variables sans rien changer au déroulement ne change pas cette difficulté.Citation:
Un exemple parmis tant d'autres, en C, dans lequel l'utilisation du goto *peut* sembler adaptée:
Et, pourtant, un algorithme très légèrement différent permettra de s'en passer:Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 int** mafonct(int n1,int n2) { int** temp; int i; int j; temp=malloc(sizeof(int*)*n1); if(temp==NULL) goto Err1; for(i=0;i<n1;i++) { temp[i]=malloc(sizeof(int)*n2); if(temp[i]==NULL) goto Err2; } return temp; Err2: for(j=0;j<i;j++) free(temp[j]); Err1: free(temp); return NULL; };
Les deux codes sont exactement équivalents: il alloue tous les deux la mémoire pour une matrice d'entier de n1 lignes et de n2 colones...Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 int** fonct2(int n1,int n2) { int errcode=0; int i; int j; int** temp; temp=malloc(sizeof(int*)*n1); if(temp==NULL) errcode=1; else { while(errcode==0 && i<n1) { temp[i]=malloc(sizeof(int)*n2); if(temp[i]==NULL) errcode=2; else i++; } } switch(errcode) { case 2: for(j=0;j<i;j++) free(temp[i]); case 1: free(temp); temp=NULL; break; } return temp; }
redécouper en fonctions implique un cout de performance pour les appels ou de mémoire dans le cas d'inline...
je n'ai pas dit que c'était toujours vrai, j'ai dit qu'il existe de tres rares cas ou le goto peut éventuellement servir.
ne me fait pas dire ce que je n'ai pas dit, j'ai le goto en horreur.