IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

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

Langage C++ Discussion :

Implémentation classe vérifant nom de fichier


Sujet :

Langage C++

  1. #1
    Membre du Club
    Profil pro
    Enseignant
    Inscrit en
    Septembre 2011
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Septembre 2011
    Messages : 43
    Points : 46
    Points
    46
    Par défaut Implémentation classe vérifant nom de fichier
    Dans le logiciel que je maintiens, je me retrouve avec ce morceau code (répété ... trop de fois):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    if ( args["action"]=="play" && args["filename"]!="") {
       string pathMusic;
       if (args["filename"][0]!='/')
           pathMusic = scriptMgr->get_script_path() + args["filename"];
       else
           pathMusic = args["filename"];
           media->audioMusicLoad(pathMusic);
    }
    En gros, si args["filename"] != 0 on informe le logiciel qu'on a un nom de fichier. Si ce nom de fichier n'est pas un nom de fichier exprimé de manière absolue, alors on modifie le nom du fichier en rajoutant un chemin indiqué par scriptMgr->get_script_path()

    Le code fonctionne pour ce qu'on lui demande mais il n'y a aucun contrôle de l’existence du fichier par exemple !

    Je souhaite alors modifier cela et faire disparaître cette horreur.

    J'ai crée une classe qui s'occupe de faire mes tests plus proprement.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class FilePath
    {
    public:
    	FilePath(std::string fileName);
    	std::string getExtention();
    	std::string getPath();
    	std::string toString();
    	bool exist();
    private:
    	...
    };
    exist() est une fonction qui vérifie vraiment l'existence du fichier sur le disque dur et que son accès est possible.
    Enfin le constructeur FilePath fait son travail de vérification des noms du fichier

    Mon morceau de code devient alors

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    if ( args["action"]=="play" && args["filename"]!="") {
       FilePath myFile = FilePath(args["filename"]);
                if (myFile.exist())
                    media->audioMusicLoad(myFile.toString());
                else
                    debug_message = _("command 'audio': filename not found");
    }
    Je l'ai mis en place sur un cas et cela fonctionne bien mieux.
    Mais je trouve mon code final peu élégant. Aussi je viens vers vous pour me donner des pistes afin de m'améliorer !

    Cordialement

  2. #2
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Il y a moyen de faire un poil mieux avec les opérateurs de conversion.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    if ( args["action"]=="play" && args["filename"]!="") {
        if (FilePath myFile = FilePath(args["filename"]))
            media->audioMusicLoad(myFile);
        else
            debug_message = _("command 'audio': filename not found");
    }
    Pour faire cela, il suffit d'ajouter deux opérateurs de conversions.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class FilePath
    {
    public:
    	FilePath(std::string fileName);
    	std::string getExtention();
    	std::string getPath();
    	std::string toString();
    	bool exist();
     
    	explicit operator bool() const { return exist(); }
    	operator std::string() const { return toString(); }
    private:
    	...
    };
    Cela dit, le second n'est pas requis si tu crées une surcharge de audioMusicLoad qui prend un FilePath en argument.

    Pour faire plus esthétique, il faudrait avoir plus de code, pour revoir éventuellement l'architecture technique.

    Tu pourrais envisager une map de foncteurs telle que std::map< std::string, std::function<void, decltype(args)>.
    Voire une classe de base
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    template <typename Args_type, typename Result = void>
    class Action {
    public:
        using arguments_type = Args_type;
        using result_type = Result;
     
        Result handle(Args_type const& args) {
            if (!verify(args)) throw action_error( _("command 'audio': filename not found") );
            do_handle(args);
        }
    private:
        virtual bool verify(Args_type const& args) const { return true; }
        virtual Result do_handle(Args_type const& args) = 0;
    }
    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

  3. #3
    Membre du Club
    Profil pro
    Enseignant
    Inscrit en
    Septembre 2011
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Septembre 2011
    Messages : 43
    Points : 46
    Points
    46
    Par défaut
    Merci !!!

    Je pensais pas que l'on pouvait réduire à ce point !

    En tout cas, cela représente au final exactement ce que je cherchais !

    Merci pour l'idée de la map de foncteurs, je vais regarder cela .

  4. #4
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    J'ai oublié d'expliquer le pourquoi

    On peut déclarer une variable dans le test d'un if, pour peu que son type soit convertible (explicitement) en booléen.
    Cette variable est définie pour l'intégralité du test (la condition, le code du "then" et celui du else).

    La conversion vers string semble ici être une bonne idée, pour la rendre transparente, mais il faut éviter de le faire.

    Attention, la conversion vers bool devrait toujours être explicit, ce qui n'était pas possible avant C++11, et est la cause du "safe bool idiom".
    Quand ce n'est pas le cas, le type peut être converti indirectement en nombre.
    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

  5. #5
    Membre du Club
    Profil pro
    Enseignant
    Inscrit en
    Septembre 2011
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Septembre 2011
    Messages : 43
    Points : 46
    Points
    46
    Par défaut
    Je digresse mais ma curiosité bat son plein avec ton indication:

    Voici la portion complète de la fonction qui me pose problème

    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
    50
    51
    52
    53
     
    int AppCommandInterface::command_audio()
    {
    	status = 1;
    	if (args["action"] != "") {
    		if (args["action"]=="drop") {
    			media->audioMusicDrop();
     
    		} else if (args["action"]=="sync") {
    			media->audioMusicSync();
     
    		} else if (args["action"]=="pause") {
    			media->audioMusicPause();
     
    		} else if ( args["action"]=="play" && args["filename"]!="") {
     
    			string pathMusic;
    			if (args["filename"][0]!='/')
    				pathMusic = scriptMgr->get_script_path() + args["filename"];
    			else
    				pathMusic = args["filename"];
    			media->audioMusicLoad(pathMusic);
     
    			media->audioMusicPlay(args["loop"]=="on");
    		} else if ( args["action"]=="load" && args["filename"]!="") {
    			string pathMusic = scriptMgr->get_script_path() + args["filename"];
    			media->audioMusicLoad(pathMusic);
    		} else if (args["action"]=="play") {
    			media->audioMusicPlay(false);
    		} else if (args["action"]=="resume") {
    			media->audioMusicResume();
    		} else {
    			debug_message = _("command 'audio': unknown action parameter");
    			Log.write( debug_message,cLog::ERROR, cLog::SCRIPT );
    			status = 0;
    		}
    		return execute_command_status();
    	}
     
    	if (args["volume"]!="") {
    		if (args["volume"] == "increment") {
    			media->audioVolumeIncrement();
    		} else if (args["volume"] == "decrement") {
    			media->audioVolumeDecrement();
    		} else media->audioSetVolume(eval_int(args["volume"]));
    		return execute_command_status();
    	}
     
    	debug_message= _("command 'audio' : unknown argument");
    	Log.write( debug_message,cLog::ERROR, cLog::SCRIPT );
    	status = 0;
    	return execute_command_status();
    }
    args est un std::map< std::string, std::string >

    est ce que je pourrais traiter les args[...] autrement qu'avec la méthode :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (args["machin"] == "bidule")
    ta piste sur la map de foncteur pourrait elle encore m'aider ?

  6. #6
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    En fait, tu peux difficilement faire beaucoup mieux: le ratio de "signal/bruit" de ton code est proche de une ligne utile par ligne.

    Par contre, tu as un bug: si la commande est "play" mais filename est vide, la fonction retourne execute_command_status() alors qu'elle n'a rien fait.
    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

  7. #7
    Membre du Club
    Profil pro
    Enseignant
    Inscrit en
    Septembre 2011
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Septembre 2011
    Messages : 43
    Points : 46
    Points
    46
    Par défaut
    Je vais donc modifier ce code avec tes informations et le rendre plus clair.

    Encore merci !

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Ne peux-tu pas utiliser des enum ou entier au lieu de string partout ?
    Les string c'est de loin le pire à manipuler pour ce genre de trucs. Avec des valeurs entières (ou enum), tu aurais un élégant switch et gagnerais quelques perfs au passage.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  9. #9
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par ternel Voir le message
    La conversion vers string semble ici être une bonne idée, pour la rendre transparente, mais il faut éviter de le faire.
    Pourquoi ? Pourquoi avec string en particulier ?

  10. #10
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Effectivement, une enum serait utile, mais ne change pas grand chose au problème.
    La chaine vient d'une ligne de commande ou d'un script, et il faut la relier à l'enum.
    Le plus rapide pour le faire sera alors une map, pour ne comparer qu'à au plus log(nombre_commandes), et non N pour une chaine de if / else if.
    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

  11. #11
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    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 : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Un détail dont il faut de méfier avec les maps, c'est que chaque accès provoque une recherche dans la table, et ici args["action"] est répété de nombreuses fois, on pourrait faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int AppCommandInterface::command_audio() {
    	status = 1;
            auto&& argAction = args["action"];  // unique recherche effectuée
    	if ( !argaction.empty() ) {
    		if ( argAction == "drop" ) {
    			media->audioMusicDrop();
    		} else if ( argAction == "sync" ) {
    			media->audioMusicSync();
                    ...

  12. #12
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,
    Citation Envoyé par Bktero Voir le message
    Pourquoi ? Pourquoi avec string en particulier ?
    Pour une raison toute bête: la comparaison de deux chaines de caractères compte parmi les comparaisons qui prennent le plus de temps.

    En effet, la comparaison de deux valeur numérique (comme des entiers) se fait en une seule instruction processeur, mais, pour comparer deux chaines de caractères, il faut comparer les valeurs numérique de ... chaque caractère d'une chaine avec le caractère se trouvant à la même position dans l'autre chaine.

    Utiliser une std::map<std::string,std::string> va déjà poser des problèmes pour le classement, parce que l'opérateur < agit de la même manière que l'opérateur == (il n'y a que l'instruction processeur qui change), ce qui fait que tu va déjà perdre du temps lors de la recherche de la clé qui t'intéresse.

    Mais si, en plus, tu t'amuse à comparer la valeur obtenue grâce à cette clé avec d'autres chaines de caractères, tu augmente encore le temps nécessaire ) l'obtention de la réponse, surtout si ... tu multiplies à loisir les valeurs potentielles pour la valeur.

    En remplaçant avantageusement une std::map<std::string, std::string> par une std::map<EnumKey, EnumValue> (où EnumKey et EnumValue seraient des énumérations ou, au pire des constantes numériques), tu peux en arriver à "booster" les performances à un niveau que tu n'aurais jamais oser atteindre
    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

  13. #13
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Je suis parfaitement d'accord dans le cas général.
    Mais dans le cas présent, chaque valeur chaine en entrée n'est utilisée qu'une seule fois (si la recherche est factorisée comme le suggère dalfab)

    Il faut bien à un moment donné chercher la chaine parmi les chaines valides. Que ce soit pour sélectionner la bonne commande à exécuter ou pour trouver la bonne valeur d'enum qui permet de trouver la commande.

    Par contre, on y gagne en découplage: on valide d'abord, puis on suit la logique demandée.
    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. Cas où nom de classe différent nom de fichier
    Par totojava dans le forum Entrée/Sortie
    Réponses: 2
    Dernier message: 08/04/2015, 20h17
  2. Connaître le nom du fichier exécutant une classe
    Par chaosinf dans le forum Langage
    Réponses: 9
    Dernier message: 19/09/2011, 13h27
  3. Implémenter un nom de fichier en C
    Par mecaplus dans le forum C
    Réponses: 10
    Dernier message: 18/03/2010, 11h17
  4. Pourquoi nom de la classe = nom du fichier PHP?
    Par aiss57 dans le forum Flex
    Réponses: 2
    Dernier message: 30/06/2009, 10h13
  5. Réponses: 8
    Dernier message: 23/06/2006, 22h53

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