Pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter, inscrivez-vous gratuitement !

 

  1. #1
    Membre régulier
    Homme Profil pro
    Webmaster
    Inscrit en
    mars 2008
    Messages
    106
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : mars 2008
    Messages : 106
    Points : 110
    Points
    110

    Par défaut Fonctionement de try / catch et throw

    Bonjour,

    je teste le fonctionnement de try / catch et throw.

    Je suis devant une erreur que je ne comprend pas.

    En passant en argument un nombre, le programme imprime la suite des nombre le composant.
    Il y a deux compteurs.

    L'objectif est de vérifier que l'argument est bien un nombre. Si cela n'est pas le cas, try catch et trhrow prend le relais.
    La compilation se passe bien. Mais, j'ai un "segmentation fault" lors des essais.

    C'est ce dernier que je ne comprend pas.

    Voici mon ecm:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
     
    #include <stdio.h> // printf
    #include <string> // stoi
    #include <iostream> // cerr cout
     
    using namespace std;
     
    // Déclaration des fonctions
    int nombreEntier(char *chaine);
     
    // Fonction Principale
    int main(int argc,char *argv[]){
    	int n=0;
    	int i=0;
    	int compte=1;
    	int decompte=0;
     
    	try{
    		n = nombreEntier(argv[1]);
    	}
    	catch(string const& err){
    		cerr << err << endl;
    		return 0;
    	}
    	decompte=n;
    	cout << decompte--;
    	while(i < n){
    		cout << ',' << compte << ',' ; 
    		compte++;
    		cout << compte << ',' << decompte << ',';
    		decompte--;
    		cout << decompte ;
    		i=i+4;
    	}
    	cout << endl;
    	printf("%d", n);
    }
     
    int nombreEntier(char *chaine){
    	int y; // indice
    	int correct=1;
    	while(chaine[y] != '\0'){
    		if(chaine[y] < '0' || chaine[y] > '9') correct = 0;
    		y++;
    	}
    	if(correct == 0) throw string("\nUniquement un nombre entier!\n");
    	else
    		return stoi(chaine);
    }
    Si quelqu'un a une idée, une piste...

    Cordialement

  2. #2
    Membre expert
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    décembre 2015
    Messages
    781
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : décembre 2015
    Messages : 781
    Points : 3 971
    Points
    3 971

    Par défaut

    Ligne 40 : y n'est pas initialisé

  3. #3
    Membre régulier
    Homme Profil pro
    Webmaster
    Inscrit en
    mars 2008
    Messages
    106
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : mars 2008
    Messages : 106
    Points : 110
    Points
    110

    Par défaut

    Citation Envoyé par dalfab Voir le message
    Ligne 40 : y n'est pas initialisé
    Comme quoi, pourquoi chercher compliquer?

  4. #4
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    août 2003
    Messages
    5 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : août 2003
    Messages : 5 214
    Points : 10 549
    Points
    10 549

    Par défaut

    L'option `-Wall` de clang++ le voit ça normalement.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  5. #5
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    Consultant informatique
    Inscrit en
    octobre 2004
    Messages
    10 863
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : octobre 2004
    Messages : 10 863
    Points : 25 138
    Points
    25 138

    Par défaut

    Salut,

    Quelques remarques au passage:

    1- On N'UTILISE PAS la directive using namespace std; : cette fonctionnalité a été proposée au tout début de la standardisation, quand il a été décidé de faire passer le contenu de la bibliothèque standard dans l'espace de nom std, pour permettre à la base de code existante (qui utilisait une version de la SL qui se trouvait dans l'espace de noms global) de continuer à compiler avec "un minimum de modifications".

    Mais elle pose énormément de problèmes du simple fait qu'elle "brise" la système d'espaces de noms. Tu as très largement intérêt à prendre l'habitude de préfixer les éléments qui viennent de la SL de std::; après tout, tu ne risque pas vraiment d'user ton clavier en le faisant, et cela ne prend pas tellement de temps de le faire

    2- au lieu de transmettre un char * à ta fonction nombreEntier, transmet une std::string, sous forme de référence constante: std::string est la classe qu'il te faut pour manipuler des chaines de caractères (voir le (4) )

    3- Traditionnellement, le catch prend place à la fin de la fonction, juste avant l'éventuel retour qui pourrait survenir lorsque "tout s'est bien déroulé". Un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    try{
    	n = nombreEntier(argv[1]);
    	decompte=n;
    	cout << decompte--;
    	while(i < n){
    		cout << ',' << compte << ',' ; 
    		compte++;
    		cout << compte << ',' << decompte << ',';
    		decompte--;
    		cout << decompte ;
    		i=i+4;
    	}
    	cout << endl;
    	printf("%d", n);
    }
    catch(string const& err){
    	cerr << err << endl;
    		return 0;
    }
    (je n'ai fait que déplacer une partie de la logique )
    produira exactement le même résultat, mais garde toute la logique "normale" "groupée" car tout ce qui est sensé bien se dérouler se trouve dans le try

    4- Pourquoi utiliser printf La sortie standard en C++, c'est std::cout.

    printf est une fonction issue du C, et, bien que C++ ne renie pas son héritage venu du C, il faut bien comprendre que ce sont deux langages totalement différents.

    5- 0 est la valeur que le système d'exploitation s'attend à recevoir lorsque tout s'est correctement déroulé. Lorsque tu te trouves dans le catch, c'est, justement, que ton application dans laquelle ton application a "rencontré un problème" et n'a pas pu se dérouler correctement.

    En renvoyant 0 au système d'exploitation, tu lui ments... renvoie plutot EXIT_FAILLURE qui correspond à une valeur que le système d'exploitation pourra considérer comme... le fait que "quelque chose a foiré"

    6- la toute dernière ligne de la fonction main devrait toujours être return 0;!

    Après tout, le prototype de cette fonction est int main() ou int main(int argc, char ** argv), et le système d'exploitation utilise la valeur renvoyée pour savoir comment s'est déroulée l'application.

    Si on arrive à la fin de la fonction main, c'est que tout s'est correctement déroulé, et il faut donc tenir le système d'exploitation au courant de ce fait.

    Note que la norme accepte effectivement à titre exceptionnel que la fonction main ne se termine pas par l'instruction return, mais, comme tout compilateur "bien réglé" va te crier dessus si tu oublie le return final d'une fonction qui est sensée renvoyer quelque chose, autant prendre l'habitude de rajouter cette instruction pour chaque fonction susceptible de renvoyer quelque chose, y compris pour la fonction main.

    7- Le type de correct, dans ta fonction nombreEntier, devrait être bool vu que tu ne t'attends qu'à avoir deux valeur possibles : vrai ou faux

    8- Je sais que le code que tu as écrit n'est destiné qu'à te servir d'essai pour l'utilisation de try ... catch, mais l'exemple est vraiment mal choisi dans le cas présent.

    En effet, les exceptions sont destinées à représenter ... des situations exceptionnelles, dont le développeur "ose espérer" qu'elles ne se produiront jamais, sans pour autant pouvoir garantir que ce sera effectivement le cas, parce que les données qu'il manipule viennent "de l'extérieur".

    Or, dans le cas présent, c'est le développeur qui décide des valeurs qui seront transmises comme paramètres à la fonction nombreEntier. Si ces valeurs ne sont pas correctes, nous sommes donc face à une erreur de logique de sa part.

    Cela sous entend que, si une erreur survient, le développeur devra corriger la logique avant de mettre son application en production, et donc que l'erreur ne pourra plus se produire une fois l'application en production.

    En un mot comme en cent, nous sommes face à ce que l'on appelle une précondition en programmation par contrat.

    Et les préconditions sont typiquement le genre de choses qui devraient être vérifiées à l'aide d'assertions, qui pourront être transformées en "no-op" quand l'application passera en production

    9- Quand la fonction main utilise le prototype int main (int argc, char * argv[]), argc correspond au nombre de chaine de caractères que l'on a utilisée pour lancer l'application.

    argv[0] correspondra d'office au nom de l'application (éventuellement avec le chemin absolu qui permet d'y accéder, selon le système d'exploitation) et les paramètres correspondront à argv[1] ... argv[argc-1].

    Tu dois systématiquement t'assurer avant toute chose qu'il aura fourni le nombre de paramètres auquel tu t'attends .

    Si ton application s'appelle myapp et que tu t'attends à recevoir une chaine de caractères comme paramètre, tu dois te dire que l'utilisateur est un imbécile distrait, et que tu dois donc t'attendre aussi bien à ce qu'il essaye de lancer l'application sous la forme de
    que sous la forme de (qui est ce à quoi tu t'attends)
    que sous la forme de
    La première et la troisième forme pour lancer ton application ne peuvent pas fonctionner car elles ne correspondent clairement pas à ce à quoi tu t'attends.

    Pire encore: ton code, tel qu'il se présente (en essayant de transmettre directement argv[1] lors de l'appel à nombreEntier risque de faire planter ton application dans le premier cas.

    Tu dois donc prendre l'habitude de mettre systématiquement en doute tout ce que l'utilisateur pourra introduire comme donnée car, si tu pars du principe que "bah, l'utilisateur sait ce qu'il fait", tu peux te dire qu'il y a neuf chances sur dix qu'il fasse une connerie, en vertu de la loi de finagle

    Par contre, si tu pars du principe que "je m'attends toujours au pire, comme cela je ne serai jamais déçu", et que tu vérifies toujours "plutôt deux fois qu'une" que l'utilisateur n'a pas introduit une connerie, tu pourras affirmer sans crainte que "oui, je suis sur que mon application réagira correctement"

    10- La règle est toujours de déclarer les variables au plus près de leur utilisation. Le code final de ta fonction main devrait donc ressembler à quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    int main(int argc,char *argv[]){
        try{
            if(argc!= 2){
                throw std::string("usage : application_name <some string>");
            }
            int n = nombreEntier(argv[1]);
            int decompte=n;
    	cout << decompte--;
            int i=0;
            int compte = 1;
    	while(i < n){
                cout << ',' << compte << ',' ; 
                compte++;
                cout << compte << ',' << decompte << ',';
                decompte--;
                cout << decompte ;
                i=i+4;
    	}
            cout << endl;
        }
        catch(string const& err){
            cerr << err << endl;
            return 1;
        }
        return 0;
    }
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Membre expert
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    avril 2016
    Messages
    697
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : avril 2016
    Messages : 697
    Points : 3 088
    Points
    3 088

    Par défaut

    @koala01 : +1 pour la majorité de ton message, mais :
    Citation Envoyé par koala01 Voir le message
    2- au lieu de transmettre un char * à ta fonction nombreEntier, transmet une std::string, sous forme de référence constante: std::string est la classe qu'il te faut pour manipuler des chaines de caractères (voir le (4) )
    Le type le plus pertinent en paramètre de nombreEntier est std::string_view (passé par valeur), car :
    • Si le paramètre est de type std::string const& et l'argument de type char const*, alors cela force une conversion qui peut coûter une allocation dynamique, sauf en cas de SSO (Small String Optimization).
    • Si le paramètre est de type std::string const& ou char const*, alors on ne peut passer que des chaînes qui se terminent par '\0'.

  7. #7
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    août 2004
    Messages
    5 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : août 2004
    Messages : 5 430
    Points : 15 712
    Points
    15 712

    Par défaut

    Citation Envoyé par Pyramidev Voir le message
    @koala01 : +1 pour la majorité de ton message, mais :

    Le type le plus pertinent en paramètre de nombreEntier est std::string_view (passé par valeur)
    Dans l'absolu, je suis d'accord avec toi. Sauf que std::string_view possède deux problèmes majeurs dans ce cas :
    - std::string_view est relativement récent, tous les compilateurs en service ne l'ont pas forcément
    - std::string_view est plus compliqué à utiliser que std::string car elle a une sémantique de référence, et j'ai déjà vu des développeurs C++, même expérimentés, se casser les dents là dessus. Alors, certes, le gain de perfs en vaut probablement la chandelle, dans du vrai code, mais j'hésiterais à en parler à quelqu'un au début de son apprentissage...
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    Consultant informatique
    Inscrit en
    octobre 2004
    Messages
    10 863
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : octobre 2004
    Messages : 10 863
    Points : 25 138
    Points
    25 138

    Par défaut

    Citation Envoyé par Pyramidev Voir le message
    @koala01 : +1 pour la majorité de ton message, mais :

    Le type le plus pertinent en paramètre de nombreEntier est std::string_view (passé par valeur)
    J'eu -- effectivement -- pu parler de std::string_view.

    Mais je rejoins malgré tout l'avis de JolyLoic, car c'est la raison principale pour laquelle je ne l'ai pas fait

    De plus, quand tu dis
    • Si le paramètre est de type std::string const& ou char const*, alors on ne peut passer que des chaînes qui se terminent par '\0'.
    j'ai quand même envie de répondre "raison de plus"!

    Car, si tu regardes attentivement le code fourni par Zuthos, tu remarqueras qu'il utilise une boucle basée sur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while(chaine[y] != '\0'){
    Le truc, c'est que je n'oserais jurer que le passage de argv[1] sous forme de const char * fournira d'office le '\0' final.

    Je crois que c'est le cas, car, autrement, nous n'aurions aucun moyen de repérer les différentes chaines de caractères, mais comme j'ai la flegme d'aller vérifier dans la norme C, je préfère "m'attendre au pire pour ne jamais être déçu" et considérer que ca risque de ne pas être le cas
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #9
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    juin 2007
    Messages
    5 111
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : juin 2007
    Messages : 5 111
    Points : 16 767
    Points
    16 767

    Par défaut

    Citation Envoyé par koala01 Voir le message
    Car, si tu regardes attentivement le code fourni par Zuthos, tu remarqueras qu'il utilise une boucle basée sur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while(chaine[y] != '\0'){
    Le truc, c'est que je n'oserais jurer que le passage de argv[1] sous forme de const char * fournira d'office le '\0' final.

    Je crois que c'est le cas, car, autrement, nous n'aurions aucun moyen de repérer les différentes chaines de caractères, mais comme j'ai la flegme d'aller vérifier dans la norme C, je préfère "m'attendre au pire pour ne jamais être déçu" et considérer que ca risque de ne pas être le cas
    D'après cppreference.com, on a bien des "null-terminated multibyte strings". Par ailleurs argc[argv] est garanti d'être un pointeur nul.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Try, catch dans une fonction
    Par mactwist69 dans le forum Windows Forms
    Réponses: 10
    Dernier message: 10/07/2008, 16h39
  2. Try/ catch dans une fonction ActionPerformed
    Par thomas2929 dans le forum Langage
    Réponses: 13
    Dernier message: 09/06/2008, 12h06
  3. Fonction du composant FTP -> Try Catch
    Par kilian dans le forum C++Builder
    Réponses: 4
    Dernier message: 04/01/2007, 10h21
  4. Réponses: 3
    Dernier message: 13/12/2006, 16h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo