Le compilateur a parlé (j'ai supprimé conio.h d'où le décalage sur les lignes)
test.cpp: Dans la fonction « void loadBrain() »:
test.cpp:60:30: warning: comparaison d'expressions entières de types signés différents: « int » et « std::__cxx1998::vector<float, std::allocator<float> >::size_type » {aka « long unsigned int »} [-Wsign-compare]
for(int cnt = 0; cnt < brain.connections.size(); cnt++)
~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp: Dans la fonction « void saveBrain() »:
test.cpp:81:26: warning: comparaison d'expressions entières de types signés différents: « int » et « std::__cxx1998::vector<float, std::allocator<float> >::size_type » {aka « long unsigned int »} [-Wsign-compare]
for(cnt = 0; cnt < brain.connections.size(); cnt++);
~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:81:9: warning: cette instruction « for » ne protège pas… [-Wmisleading-indentation]
for(cnt = 0; cnt < brain.connections.size(); cnt++);
^~~
test.cpp:82:9: note: …cette instruction, mais l'indentation de cette dernière est trompeuse car elle fait croire qu'elle est gardée par le « for »
{
^
test.cpp: Dans la fonction « void generateBrain() »:
test.cpp:109:26: warning: comparaison d'expressions entières de types signés différents: « int » et « std::__cxx1998::vector<float, std::allocator<float> >::size_type » {aka « long unsigned int »} [-Wsign-compare]
for(int cnt = 0; cnt < brain.connections.size(); cnt++)
~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:114:68: warning: utilisation d'un vieux style de transtypage vers « float » [-Wold-style-cast]
putConnectionValue(cnt1, cnt2, cnt3, (((float)rand()/(float)(RAND_MAX)) * 2) - 1);
^
-------------
static_cast<float> (rand())
test.cpp:114:86: warning: utilisation d'un vieux style de transtypage vers « float » [-Wold-style-cast]
putConnectionValue(cnt1, cnt2, cnt3, (((float)rand()/(float)(RAND_MAX)) * 2) - 1);
^
-----------------
static_cast<float> ((RAND_MAX))
test.cpp: Dans la fonction « int main() »:
test.cpp:120:41: warning: zéro comme constante de pointeur nul [-Wzero-as-null-pointer-constant]
srand (static_cast <unsigned> (time(0)));
^
test.cpp:125:30: warning: la conversion de « std::basic_istream<char>::int_type » {aka « int »} vers « char » peut changer la valeur [-Wconversion]
choice = std::cin.get();
~~~~~~~~~~~~^~
test.cpp: Au niveau global:
test.cpp:140:1: warning: la macro « debug » n’est pas utilisée [-Wunused-macros]
}
^
Et un des warnings est clairement une erreur. Il faut activer les avertissements.
> r
Starting program: /home/jonathan/rawdisk2/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so.1".
[L]oad brain_file
[G]enerate a random brain_file
[Q]uit program
g
Number of layers:3
Number of node in layer 1: 3
Number of node in layer 2: 3
Number of node in layer 3: 3
/usr/sbin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/debug/vector:417:
Error: attempt to subscript container with out-of-bounds index 100, but
container only holds 0 elements.
Objects involved in the operation:
sequence "this" @ 0x0x5555560202e0 {
type = std::__debug::vector<float, std::allocator<float> >;
}
Program received signal SIGABRT, Aborted.
0x00007ffff7aabd7f in raise () from /usr/lib/libc.so.6
> bt
#0 0x00007ffff7aabd7f in raise () from /usr/lib/libc.so.6
#1 0x00007ffff7a96672 in abort () from /usr/lib/libc.so.6
#2 0x00007ffff7e946c6 in __gnu_debug::_Error_formatter::_M_error (this=0x555556020380 <__gnu_debug::_Error_formatter::_M_at(char const*, unsigned int)::__formatter>) at /build/gcc/src/gcc/libstdc++-v3/src/c++11/debug.cc:1069
#3 0x0000555555698600 in std::__debug::vector<float, std::allocator<float> >::operator[] (this=0x5555560202e0 <brain+64>, __n=100) at /usr/sbin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/debug/vector:417
#4 0x0000555555695059 in putConnectionValue (xbrain_layer=1, xbrain_line=0, xbrain_column=0, connection_value=-0.225964546) at test.cpp:41
#5 0x0000555555697baa in generateBrain () at test.cpp:114
#6 0x000055555569814e in main () at test.cpp:132
Tu devrais aussi regarder comment fonctionne un débogueur pour trouver les erreurs (ici c'est gdb)
fread, fwrite peuvent être utilisées en C++, parce qu'historiquement la bibliothèque standard de C est incluse dans celle de C++. Mais, car il y a un mais, C++ propose une autre approche qui colle mieux avec l'esprit du langage et ses spécificités, ce sont les flux (ofstream/ifstream pour les flux fichiers). La notion de flux telle que présentée par C++ est indépendante de celle de fichier, par son biais je peux travailler de la même façon avec n'importe quel périphérique E/S. Au niveau de mes objets je me fous complètement que les E/S soient faites sur un fichier, une connexion réseau, une base de données, un GUI, le code est le même, ce sont les spécialisations des flux qui font la différence. C'est quasiment le seul intérêt de la POO (je définis une abstraction métier que je spécialise, ce qui me permet de travailler avec un grosse partie de mon code qui es purement générique, je l'ai écrite une fois elle servira pour tous les cas sans que j'ai à en changer une virgule).
Ton prof t'as raconté des conneries, la bonne pratique en C++, c'est de travailler avec des flux. Les flux peuvent s'interfacer avec les autres éléments de la bibliothèque standard pour former un ensemble cohérent, si tu penses bien ton truc adieu les cast void* sans la moindre garantie, tu implémentes les extracteurs qui vont bien et tu obtiens à l'arrivée un truc robuste qui tient la route et les performances, et qui cerise sur le gâteau est relativement facile à tester tout en étant générique.
Ok merci pour les précisions, de toute façon je trouve ça aussi plus simple avec des flux !
Par contre il me disait que je pouvais utiliser f.read et f.write (le '.' en plus) propre au C++, je ne pense pas que ça fasse une grande différence mais je le précise tout de même.
Et j'ai aussi modifié la déclaration du vector pour avoir un vrai vector à 3 dimensions et non un simili fait avec un vector unidimensionnel.
les defines -> vraie variable constante (const ou mieux, constexpr).
include <string.h> -> include <cstring> (et les autres). Les includes provenant du C ont un en-tête C++ préfixés par c et sans .h. Au passage, même pas sûr que tu aies besoin de cstring.
typedef struct { ... } XX; -> clairement une syntaxe du C, en C++ on fait struct XX { ... };
j'ai corrigé le code mais je n'arrive pas supprimer 'using namespace std;' sans avoir des erreurs sur les 'ifstream' et 'ofstream', et le 'typedef' non-plus
Je peux juste enlever <cmath> sans erreurs, de plus je peux mettre des "std::" devant les "string", "vector" ect mais pas les "ifstream" et "ofstream".
Je ne comprends pas pourquoi tu veux que j'enlève ces library alors qu'elles servent partout dans mon code ?
Bah merci ça fait toujours plaisir, donnes-moi plutôt des solutions plutôt que de me blâmer sur tel ou tel point et je ne comprends pas non-plus pourquoi le C est un problème, ou alors il y a des équivalents en C++ que je ne connais pas ?
Je tiens aussi à préciser que je ne fait pas d'études en informatique mais en électronique et en informatique INDUSTRIELLE où on apprends notamment le C et un petit peu le C++ donc mon Prof n'aura pas ce genre d'exigences, et s'il les avait ce ne serait pas justifié car j'ai appris tout seul ce que je programme actuellement.
Et puis le nombre de 'if' ? Pardon j'en ai mis 3 qui testent si le fichier est bien ouvert !
Je sais que ça part d'une bonne intention mais ta réponse ne m'aide pas au contraire.
Dans Informatique Industrielle, il y a Informatique, donc désolé, mais les exigences sont justifiées De toute façon, vouloir faire du C ou du C++ sans ces exigences, c'est du suicide. C++ et encore plus C, sont des langages de programmation qui ne tolèrent vraiment pas l'à peu près. Tu te prépares à l'informatique industrielle, au niveau de la rigueur, c'est probablement pas loin de l'exigence maximale, n'oublie pas que si tu te rates, c'est la production d'une usine entière qui peut partir à la poubelle... La responsabilité est énorme!
Mon conseil, c'est de découper ton code en fonctions les plus courtes possibles, 2 if dans une fonction, c'est très souvent un de trop, 2 boucles, idem. Plus une fonction est courte et simple, plus elle est facile à écrire, à comprendre et aussi à tester et à debugger. Diviser pour régner telle est la règle
Je connais les exigences en informatique industrielle, et elle diffèrent pas mal de tout ce que vous m'avez dit dans ce forum, par exemple on nous encourage à utiliser des 'typedef' et les if ne sont pas un problème surtout dans le cas de MAE ou de Grafcet, je ne dit pas qu'il y en a pas mais elles diffèrent grandement de la programmation "non-industrielle" c'est pourquoi la question des attentes de mon prof (d'informatique industrielle) n'est pas vraiment pertinente, je ne cherche pas à justifier ce que je code mais ce n'est pas très encourageant de lire que son code vaut 6/20 sans connaitre le contexte. Je code avec les outils que j'ai appris et que j'apprends et déjà ce code est très loin de tout ce qu'on a fait en info indus.
Ceci étant dit,
- j'ai beau relire toute la conversation je ne vois pas de substituts pour les librairies que j'utilise
- je ne vois toujours pas où y a-t-il trop de 'if'
- j'ai réduit les sous-programmes et ai enfin réussi à supprimer le 'using namespace std;'
Je n'ai pas suivi la conversation, donc quelques remarques rapides.
ThéoSarda1 a écrit:
par exemple on nous encourage à utiliser des 'typedef'
L'utilisation de typedef pour déclarer une classe est un reliquat du C. C'est pas recommandé de l'utiliser et c'est meme explicitement interdit en C++17.
The typedef specifier cannot be combined with any other
specifier except for type-specifiers.
The typedef-names are aliases for existing types, and are
not declarations of new types. Typedef cannot be used to
change the meaning of an existing type name (including a
typedef-name). Once declared, a typedef-name may only be
redeclared to refer to the same type again. Typedef names
are only in effect in the scope where they are visible:
different functions or class declarations may define
identically-named types with different meaning.
The typedef specifier may not appear in a declaration that
does not contain a declarator.
typedef struct X {}; // ill-formed [C++17]
ThéoSarda1 a écrit:
Je connais les exigences en informatique industrielle, et elle diffèrent pas mal de tout ce que vous m'avez dit dans ce forum
La lisibilité d'un code est un critère important de qualité. Si on a du mal a lire un code, on aura du mal aussi a voir les bugs.
Des choses très simples, comme tes variables (inutilement) non initialisées, c'est un risque de comportement indéterminé (UB undefined behavior), donc de comportement non désiré du logiciel.
Et il doit y avoir encore pas mal de choses qui posent problème.
En vrac :
- IntToString ne sert a rien, il existe une fonction std::to_string
- c_str() dans fstream ne sert a rien depuis le C++11
- passer brain par copie dans saveBrain, c'est moche
Bon, a force, j'ai perdu le fil, je ne sais plus quel est le problème.
`conio.h` => T'en a juste pas besoin . . . C'est pas portable
`cmath` => T'en a pas vraiment besoin, utilise une librairie pour des matrices
Pour ce qui est des `if`, au taff on a une regle qui s'avere assez vrais.
Pour une fonction, le `nombre de bug = 2^nombre de if`
Ton switch case dans le main cause de la difficulte de lecture.
Ligne 116 ton `if` rajoute inutilement de la complexite a cette fonction, alors qu'elle ne devrais pas etre appeller si le contenu c'est pas bon.
T'a des 3 boucles for complexe a lire. (Genre les Range loop c'est so 2011) fait une fonction prenant une lambda avec les positions si t'en as vraiment besoin, mais cela me parrait inutile.
Je connais les exigences en informatique industrielle, et elle diffèrent pas mal de tout ce que vous m'avez dit dans ce forum, par exemple on nous encourage à utiliser des 'typedef'
Dans les définitions de classes et de structures ? cela m'étonnerait bien fort. A moins que l'on fasse du C et non du C++
Et ceux qui te disent que
Mais de toutes façons, C et C++ c'est la même chose
n'auront décidément rien compris au C++
et les if ne sont pas un problème surtout dans le cas de MAE ou de Grafcet, je ne dit pas qu'il y en a pas mais elles diffèrent grandement de la programmation "non-industrielle"
Un if, ca donne toujours une alternative, et donc deux possibilités, car il y a toujours soit
la possibilité de faire quelque chose si la condition est remplie ET
la possibilité de ne rien faire si elle n'est pas remplie (ce qui est aussi une possibilité)
soit
la possibilité de faire quelque chose si la condition est remplie ET
la possibiilté de faire autre chose si la conditions n'est pas remplie
Dans le meilleur des cas, le nombre de possibilités (et de chemins d'exécution possibles) évolue donc de manière proportionnelle au nombre de tests (pour N tests, tu te retrouve avec 2N chemins d'exécution possibles).
Dans le pire des cas, le nombre de possibilités (et de chemins d'exécution possibles) évoluera de manière exponentielle (pour 8 tests, tu peux très bien te retrouver avec ... 256 chemins d'exécution possibles).
Ne vient donc pas dire que les if ne sont pas un problème, car c'est bel et bien un problème réel : quand tu mets une logique en place, c'est pour obtenir un résultat clairement identifié et reproductible à partir d'une situation donnée.
Si tu veux t'assurer que ton application donnera le résultat espérer, tu dois pouvoir t'assurer que tous les chemins d'exécution fourniront le résultat attendu.
Et cela signifie que tu dois pouvoir tester chaque situation possible.
Or, s'il est facile de déterminer les situations auxquelles nous seront confrontés avec une condition (elle est remplie, ou non, il y a donc "quelque chose" qui doit être fait, ou "autre chose" qui devra être fait ... voire, ou "rien du tout" qui devra être fait), la multiplication "comme des petits pains" des tests te mettra dans une position dans laquelle, au mieux, tu en viendra à tester trois fois la même possibilité (ce qui n'est pas vraiment utile) et, au pire, tu en viendra à oublier la une bonne moitié des possibilités offertes
Albert Einsthin l'a dit en son temps :
Il faut rendre les choses aussi complexes que nécessaire, mais guère plus
Ce qu'il voulait dire, c'est que l'on n'a pas vraiment le choix: nous sommes généralement confrontés à des problèmes tellement complexes que la solution qu'il faut y apporter ne peut souvent qu'être complexe.
Mais il faut toujours veiller à garder la solution "la plus simple possible", si on veut arriver à quelque chose d'efficace et d'utile.
La multiplication des tests ne permet pas de garder notre solution "la plus simple possible".
c'est pourquoi la question des attentes de mon prof (d'informatique industrielle) n'est pas vraiment pertinente, je ne cherche pas à justifier ce que je code mais ce n'est pas très encourageant de lire que son code vaut 6/20 sans connaitre le contexte.
La remarque est peut-être un peu abrupte, mais elle est justifiée
La seule chose que l'on puisse dire à ce sujet, c'est de ne pas prendre cette remarque comme une attaque personnelle, mais bien comme une incitation à faire mieux!
Enormément de remarques, d'améliorations potentielles t'ont été faites au cours de cette discussion.
Prends le temps de les relire, de les comprendre et de les appliquer.
Si tu ne les comprends pas, n'hésites pas à poser des questions, car il est vrai que de nombreuses remarques sont parfois "trop générales" pour être facilement comprises.
Et surtout, gardes bien en tête que nous sommes tous passés par là: nous avons tous écrit du code aussi mauvais que le tien! Et nous en avons tous payé les conséquences
Dis toi qu'en corrigeant tes habitudes (et ton code) maintenant, tu te facilite la vie pour les quarante ans à venir, parce que les habitudes que nous cherchons à te faire prendre te permettront, quand tu auras atteint l'age de la pension, de décider de relire le code que tu auras (corrigé) écrit aujourd'hui, de le comprendre et de l'apprécier
Je code avec les outils que j'ai appris et que j'apprends et déjà ce code est très loin de tout ce qu'on a fait en info indus.
Et nous en sommes bien conscients!
Mais dis toi bien que nous étions exactement dans la même situation que toi il y a "quelques années" (une vingtaine pour certains d'entre nous), même si nous ne sommes pas tous issus de la filière info indus.
Dis toi que nous avons appris exactement le même genre de C++ que toi, et que nous avons galéré un max pour "désapprendre" ce que l'on avait appris afin de pouvoir commencer à faire réellement du C++.
Ben oui, les habitudes, ca a la peau dure!
Et c'est la raison pour laquelle nous nous battons pour que tu prennes directement les bonnes habitudes, pour que notre expérience puisse au moins faciliter la vie et l'apprentissage des plus jeunes.
Ceci étant dit,
- j'ai beau relire toute la conversation je ne vois pas de substituts pour les librairies que j'utilise
- je ne vois toujours pas où y a-t-il trop de 'if'
- sinon ok pour réduire les sous-programmes, je m'y atèle.
- Edité par ThéoSarda1 il y a 5 minutes
C'est parce que tu cherche le mauvais éléments... Ce ne sont pas les "if" en particulier que tu dois chercher, mais les tests en général (dont les boucles).
Mais, si tu veux voir où il y en a trop, voici un exemple tiré de ton code:
sur les 24 lignes de ce code, tu as un test "vrai faux" (le if (brain_file)) et quatre tests dus à des boucles.
Parmis ces quatre tests dus à des boucles, trois des boucles sont imbriquées les unes dans les autres! Cela rend ta logique beaucoup trop complexe.
En plus, ces vingt-quatre lignes impliquent:
que tu fais de l'affichage
que tu fais de l'extraction de données à partir d'un fichier
que tu interprètes les données extraites
que tu garde une trace en mémoire des données interprétées pour "une utilisation ultérieure"
Cela, mon cher ami, cela implique que tu donne au moins quatre responsabilités à ta fonction. Et cela en fait donc au moins trois de trop.
Il y a en effet un principe primordial à garder en tête et à appliquer en toutes circonstances (en fait, il y en a quatre de plus que celui là, mais passons): le principe dit "de la responsabilité unique":
Chaque donnée, chaque type de donnée, chaque fonction, chaque "fonctionnalité" (pour utiliser un terme tout à fait générique ne peut avoir qu'une et une seule responsabilité
Autrement dit, si tu as une fonction qui s'occupe de l'affichage, elle ne doit s'occuper que de cela, et de rien d'autre.
Si tu as une fonction qui extrait des données d'un fichier, elle ne doit s'occuper que de cela et de rien d'autre: elle doit renvoyer "quelque chose" qui représente les données telles qu'elles se présentaient dans le fichier.
Si tu as une fonction qui interprète des données (extraites depuis un fichier), pour leur donner un "sens utile" au reste du traitement, elle ne doit s'occuper que de cela, et de rien d'autres (on s'attend cependant à ce qu'elle renvoie "une trace" de toutes les données qu'elle aura interprétées" )
Si tu as une fonction qui s'occupe de manipuler les données interprétées, elle ne doit... devines quoi?
Vois désormais tu plus où moins "par où ton code blesse"?
Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
OK je vois tu peux voir mon message précédant je pense avoir bien séparé mes fonctions.
Oui en info indus on voit peut de C++ et beaucoup de C mais même en C++ ils nous disaient d'utiliser des typedef, (remarque on en a fait très peu car ce n'est pas le coeur de notre formation), on n'à même pas vu les classes, je vient de me souvenir de la formulation "du C codé en C++".
"les 'for' sont des 'if' !" ça m'éclaire sur pas mal de messages mais je ne vois pas comment je peux parcourir un vecteur à trois dimension sans ces boucles. Et puis dans ce cas il n'y a pas 2 chemins je pense c'est le même chemin emprunté un certain nombre de fois (même si c'est peut-être très mal dit)
Je suis navré si j'ai pu paraître sur la défensive, je prends note de toutes les infos que vous m'offrez. Il m'arrive de m'impatienter quand on me souligne plein de problèmes et que quand je demande des solutions à ces problèmes on me répond simplement "ton code vaut 6" (je caricature un peu), je ne cherche pas à me défendre mais je reste bloqué longtemps sur ces problèmes donc je propose des solutions par moi-même qui du coup peuvent (et à raison) irriter la plupart d'entre vous.
je renote les problèmes pour faire le point:
les typedef c'est mal --> comment je m'en défait ?
les if (et donc les boucles imbriquées) c'est mal --> comment je parcours ce vecteur 3d sans ?
conio.h c'est mal --> j'ai un getch dans mes menus, y a-t-il une alternative ?
Oui en info indus on voit peut de C++ et beaucoup de C mais même en C++ ils nous disaient d'utiliser des typedef
Tu parles des entreprises ou de tes profs d'info qui te disent ca ?
Beaucoup de profs sont juste pas a jour de leur connaissances et connaissent pas le milieu pro.
Faire du C avec un compilateur C++, ca fait pas du C++.
Malheureusement, beaucoup de ceux qui continuent le C++ professionnellement sont obligés d'oublier ce qu'ils ont appris a l'ecole et doivent tout reapprendre. C'est dommage, mais c'est comme ca.
ThéoSarda1 a écrit:
les typedef c'est mal --> comment je m'en défait ?
L'une est légale en C++, l'autre est un reliquat historique.
C'est presqu'un détail. Mais en termes de maintenance du code, cela veut dire que tu pourrais avoir des problèmes avec typedef (en particulier, comme je l'ai dit, parce que ce n'est plus valide en C++17 et le compilateur pourra produire une erreur. Et donc il faudra modifier le code)
× 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.
Architecte logiciel - Software craftsmanship convaincu.
Architecte logiciel - Software craftsmanship convaincu.
Architecte logiciel - Software craftsmanship convaincu.
Architecte logiciel - Software craftsmanship convaincu.
Discord NaN. Mon site.
Architecte logiciel - Software craftsmanship convaincu.
Architecte logiciel - Software craftsmanship convaincu.
Discord NaN. Mon site.
Discord NaN. Mon site.
Discord NaN. Mon site.
Discord NaN. Mon site.
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C