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

C++ Discussion :

manipulation des références : quel type de retour ?


Sujet :

C++

  1. #1
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut manipulation des références : quel type de retour ?
    Bon mon titre parait assez simpliste (bah des références !! ), mais la question est véritable. Je me demande si ce n'est pas une erreur de conception de ma part, mais voilà un exemple typique :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    sf::Sprite& AnimHandler::getSprite()
    {
        for (auto& a : animationsVector)
            if (a.name == currentAnimationName)
                return a.currentSprite;
     
        std::cerr << "impossible d'arriver ici normalement" << std::endl;
       //ici il me manque un return...
    }
    ...sauf que je ne sais pas quoi mettre, pour que cela soit propre... et j'ai deux ou trois warnings dans mon code à cause de cela.

    Le commentaire (impossible d'arriver ici), c'est parce que l'utilisateur n'a aucun contrôle ici, et donc aucun risque que le programme atteigne ce point (parce que lui ne fait pas d'erreur d’orthographe^^).

    Alors ? Je revois mes types de retour ou vous avez un tuyau ? Ou je manque quelque chose d'énorme ? (ce qui reste possible ^^ )


    Edit : bon je sais que je pourrais utiliser les algorithmes de la STL et les lambdas à la place, mais là n'est pas la question.



    Edit2 : mon Edit viens de me faire penser à ce que fait std::find ... je renvois animationsVector.end() ? (Mais c'est pas une référence du coup ... ) je me mélange ^^
    Nullius in verba

  2. #2
    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
    Bonjour,

    (parce que lui ne fait pas d'erreur d’orthographe^^)
    Déjà je miserais pas là-dessus, parce que justement l'utilisateur est plus que source d'erreur, et l'orthographe en est une assez importante.

    Ensuite, j'ai l'impression d'avoir déjà vu ce sujet, mais le mieux amha est de retourner non pas une référence mais un pointeur. La valeur NULL pouvant servir d'erreur/non trouvé.

    iterator::end est de toutes façons plus ou moins un pointeur camouflé, mais en aucun cas une référence
    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.

  3. #3
    Membre éprouvé

    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    533
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 533
    Points : 1 086
    Points
    1 086
    Par défaut
    Une exception à la place du std::cerr ?
    Je crois que ça supprimerait le warning du return manquant, en plus.

  4. #4
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Bonjour,


    Déjà je miserais pas là-dessus, parce que justement l'utilisateur est plus que source d'erreur, et l'orthographe en est une assez importante.

    Ensuite, j'ai l'impression d'avoir déjà vu ce sujet, mais le mieux amha est de retourner non pas une référence mais un pointeur. La valeur NULL pouvant servir d'erreur/non trouvé.

    iterator::end est de toutes façons plus ou moins un pointeur camouflé, mais en aucun cas une référence
    Justement c'est ce que je disais, "lui" faisait référence à mon algo.

    Donc si je comprends bien, dans ce cas pas de moyen propre d'utiliser les références ?
    Nullius in verba

  5. #5
    screetch
    Invité(e)
    Par défaut
    Une exception pour les choses qui ne devraient pas arriver, pour que ta fonction ne retourne pas un objet invalide.

  6. #6
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    Citation Envoyé par screetch Voir le message
    Une exception pour les choses qui ne devraient pas arriver, pour que ta fonction ne retourne pas un objet invalide.
    Ok, gestion des exceptions. C'est noté. Merci^^ et merci Cob59 également.

    ça ne m'a pas enlevé le warning. Mais c'est la première fois que j'utilise vraiment les exceptions dans mon code donc qu'ai-je fais de mal ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    sf::Sprite& AnimHandler::getSprite()
    {
        try
        {
            for (auto a : animationsVector)
                if (a.name == currentAnimationName)
                    return *a.currentSprite;
        }
        catch (std::exception e)
        {
            std::cerr << "impossible d'arriver ici normalement : " << e.what() << std::endl;
        }
    }
    Nullius in verba

  7. #7
    Membre éprouvé

    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    533
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 533
    Points : 1 086
    Points
    1 086
    Par défaut
    Ah oui mais non.
    Le bloc try/catch doit se trouver dans l'appelant de AnimHandler::getSprite(). Ou simplement être absent, pour laisser l'exception se propager jusqu'au main() et faire planter (ce qui peut être un moindre mal).

  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
    Pour envoyer une exception c'est throw
    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
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    Citation Envoyé par cob59 Voir le message
    Ah oui mais non.
    Le bloc try/catch doit se trouver dans l'appelant de AnimHandler::getSprite(). Ou simplement être absent, pour laisser l'exception se propager jusqu'au main() et faire planter (ce qui peut être un moindre mal).

    Oui Cob59 c'est ce dont je me suis aperçu tout de suite après... mais du coup ça me plait pas trop. Au final cela doit être une extension d'une API pour faire les choses simplement alors si je demande à l'utilisateur de gérer les exceptions pour éviter les conneries qu'il y a dans mon code... je vais passer des pointeurs je penses que ce sera mieux pour tout le monde.

    Merci Bousk, je t'avoues que je l'avais ajouté avant que tu le dise mais que je ne savais pas vraiment à quoi il servait (je pensais que ça servait à "retenter le coup"). Je vais lire la FAQ sur les exceptions plutôt que de vous embêter plus longtemps. Merci ^^
    Nullius in verba

  10. #10
    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
    Citation Envoyé par Kaamui Voir le message
    Oui Cob59 c'est ce dont je me suis aperçu tout de suite après... mais du coup ça me plait pas trop. Au final cela doit être une extension d'une API pour faire les choses simplement alors si je demande à l'utilisateur de gérer les exceptions pour éviter les conneries qu'il y a dans mon code... je vais passer des pointeurs je penses que ce sera mieux pour tout le monde.
    Hummm...

    Oui, mais non...

    Si tu renvoies un pointeur, tu obliges, de toutes manières, l'utilisateur à vérifier la validité de celui-ci...

    S'il oublie de le faire et que, par "malchance", le sprite n'a pas été trouvé (et que la fonction renvoie NULL /nullptr), le programme finira tot ou tard par planter, et, sans doute bien loin de l'appel à getSprite()

    Cela ne va pas faciliter la vie de l'utilisateur, loin de là

    Si, par contre, tu indiques clairement dans la doc la précondition qui est "le sprite existe" et le fait que ta fonction lance une exception si le sprite n'est pas trouvé, tu ne laisses que deux solutions:
    • Soit l'utilisateur a correctement lu la doc et s'attend à gérer l'exception (et tout va bien )
    • Soit l'utilisateur n'a pas lu la doc, ne s'attend pas à devoir gérer l'exception, et le programme plante... Mais, comme il aurait de toutes façons planté sur un pointeur NULL, tu limites les dégâts.(et l'utilisateur ne peut que se mordre les doigts de n'avoir pas lu correctement la doc de la fonction )


    En plus, comme l'indique le commentaire, si le sprite n'est pas trouvé, tu es, effectivement dans une situation exceptionnelle qui ne devrait pas arriver

    Tu pourrais d'ailleurs envisager de placer une assertion juste avant de lancer l'exception qui aurait le mérite d'indiquer clairement à quel moment il y a une erreur et laquelle

    (N'oublies cependant jamais qu'un assertion n'est valide qu'en mode débug, et qu'il ne faut donc s'y fier... que dans ce mode particulier: il faut parfois une sérieuse dose de tests unitaires pour arriver à faire que l'assertion survienne )
    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

  11. #11
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Hummm...

    Oui, mais non...

    Si tu renvoies un pointeur, tu obliges, de toutes manières, l'utilisateur à vérifier la validité de celui-ci...

    S'il oublie de le faire et que, par "malchance", le sprite n'a pas été trouvé (et que la fonction renvoie NULL /nullptr), le programme finira tot ou tard par planter, et, sans doute bien loin de l'appel à getSprite()

    Cela ne va pas faciliter la vie de l'utilisateur, loin de là

    Si, par contre, tu indiques clairement dans la doc la précondition qui est "le sprite existe" et le fait que ta fonction lance une exception si le sprite n'est pas trouvé, tu ne laisses que deux solutions:
    • Soit l'utilisateur a correctement lu la doc et s'attend à gérer l'exception (et tout va bien )
    • Soit l'utilisateur n'a pas lu la doc, ne s'attend pas à devoir gérer l'exception, et le programme plante... Mais, comme il aurait de toutes façons planté sur un pointeur NULL, tu limites les dégâts.(et l'utilisateur ne peut que se mordre les doigts de n'avoir pas lu correctement la doc de la fonction )


    En plus, comme l'indique le commentaire, si le sprite n'est pas trouvé, tu es, effectivement dans une situation exceptionnelle qui ne devrait pas arriver

    Tu pourrais d'ailleurs envisager de placer une assertion juste avant de lancer l'exception qui aurait le mérite d'indiquer clairement à quel moment il y a une erreur et laquelle

    (N'oublies cependant jamais qu'un assertion n'est valide qu'en mode débug, et qu'il ne faut donc s'y fier... que dans ce mode particulier: il faut parfois une sérieuse dose de tests unitaires pour arriver à faire que l'assertion survienne )
    donc le code final correct ce serait :
    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
     
    /*!
    *
    * \brief precondition : sprite must exist. If doesn't exist, throw an exception
    */
    sf::Sprite& AnimHandler::getSprite()
    {
        try
        {
            for (auto a : animationsVector)
                if (a.name == currentAnimationName)
                     return *a.currentSprite;
     
     
            #if DEBUG
                 assert(a.currentSprite == nullptr, "le sprite n'existe pas");
            #endif    
            throw;
        }
        catch (std::exception e)
        {
            std::cerr << "impossible d'arriver ici normalement : " << e.what() << std::endl;
        }
    }
    C'est bien ça que tu imaginais ? (avec une doc un peu plus garnie mais dans l'idée)
    Nullius in verba

  12. #12
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2012
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2012
    Messages : 13
    Points : 13
    Points
    13
    Par défaut
    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
     
    /**
    *
    * \brief precondition : sprite must exist. If doesn't exist, throw an exception
    */
    sf::Sprite& AnimHandler::getSprite()
    {
        try
        {
            for (auto a : animationsVector)
                if (a.name == currentAnimationName)
                {
                 #if DEBUG
                     assert(a.currentSprite == nullptr, "le sprite n'existe pas");
                 #endif
                    return *a.currentSprite;
                 }
            throw;
        }
        catch (std::exception e)
        {
            std::cerr << "impossible d'arriver ici normalement : " << e.what() << std::endl;
        }
    }
    Je le vois plus comme ça :

    Ton exception :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    class myexception: public exception
    {
        virtual const char* what() const throw()
        {
            return "le sprite n'a pas été trouvé ";
        }
    }
    Ta fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    sf::Sprite& AnimHandler::getSprite()
    {
            for (auto a : animationsVector)
                if (a.name == currentAnimationName)
                    return *a.currentSprite;      
     
            throw myexception();
    }
    Et après l'utilisateur de ton code fera :
    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
     
    int main () 
    {
       try
        {
            getSprite();
        }
        catch (std::myexception e)
        {
            std::cerr << "impossible d'arriver ici normalement : " << e.what() << std::endl;
        }
        // Et s'il y a d'autres exceptions possibles
        catch (std::exception e)
        {
            std::cerr << "Autre exception déclenchée : " << e.what() << std::endl;
        }
     
        return 0;
    }
    Pour l'assertion je ne connais pas encore

  13. #13
    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
    Non, l'idée, c'est de lancer l'exception si l'élément n'est pas trouvé, et de laisser l'utilisateur s'en occuper...

    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
     
    /* ca peut etre "plus bas" dans une hiérarchie cohérente d'exceptions ;)
      */
    class SpriteNotFound : public std::runtime_error
    {
        /* ... */
    };
    /** find the sprite wich has currentAnimationName as name
      *
      * @pre  searched sprite must exist
      * @trhow SpriteNotFound if searched sprite is not found
      *
      */
    sf::Sprite& AnimHandler::getSprite()
    {
         for (auto a : animationsVector)
         {
             if (a.name == currentAnimationName)
             {
                     return *a.currentSprite;
             }
        }
        /* éventuellement, pour le débug */
        assert(!"curentAnimationName not found"); //nécessite l'inclusion de <cassert>
        throw SpriteNotFound();
    }
    L'assertion affichera le message en mode debug et stoppera l'exécution (avec un message proche de currentApplicationName not found in file XXX, line YYY)

    En mode release, l'exception remontera automatiquement jusqu'à... ce qu'il y ait un code susceptible de la gérer (ou fera planter l'application)

    Comme tu n'as, a prior, aucun moyen de gérer l'exception dans cette fonction particulière, c'est à l'appelant (ou à l'une des fonctions dans la pile d'appel) de la gérer "quand c'est possible"
    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

  14. #14
    Membre chevronné
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Points : 1 921
    Points
    1 921
    Par défaut
    Renvoyer un iterateur qui vaudrait otentiellement end me parait plus propre, plus idiomatique et plus simple que ce jonglage.

  15. #15
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    Citation Envoyé par Joel F Voir le message
    Renvoyer un iterateur qui vaudrait otentiellement end me parait plus propre, plus idiomatique et plus simple que ce jonglage.
    En fait je n'ai eu besoin d'aucune de ces deux solutions ; ma méthode sf::sprite& AnimHandler::getSprite() est devenue void AnimHandler::draw(sf::RenderTarget& target)Pour les autres fonctions qui restaient concernés par cette problématique, j'ai choisi d'inclure dans les préconditions une explication sur le fait que la responsabilité de l'existence des différents éléments était laissée à l'utilisateur, et que seul un message de warning serait adressé à ce dernier. J'ai fait ce choix car je me suis aperçu que toutes les méthodes concernées pouvaient ne pas empêcher le bon fonctionnement d'un programme utilisant ma lib. Si par exemple vous avez milles sprites à afficher et que vous vous êtes trompé sur un appel, il sera tout simplement ignoré, et un message warning apparaitra en console, vous avertissant que l'objet nommé "le_nom_qui_ne_devait_pas_etre_correct" n'a pas été trouvé.

    Que pensez vous de cette approche ?


    Edit : le code de draw :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    void AnimHandler::draw(sf::RenderTarget& target)
    {
       for (auto& a : animationsVector)
       {
           if (a.name == currentAnimationName)
           {
               target.draw(a.currentSprite, sf::RenderStates::Default);
               return;
           }
       }
       std::cerr << "No animation was created yet." << std::endl;
    }
    currentAnimationName étant défini par le programme (l'utilisateur n'a pas connaissance de cette variable) à partir du vector animationsVector, je trouvais un peu "too much" les propositions de Koala01 (même si surement 10 fois plus rigoureuses que ce que moi j'ai fais) pour un truc qui n'arrivera évidemment jamais.
    Nullius in verba

  16. #16
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Salut

    Ca me semble mieux a priori de rendre un service plutôt que d'avoir un accesseur.

    Sans avoir lu le reste, ton code m'étonne :
    * si currentAnimationName et a.name sont des string, c'est une mauvaise idée. La comparaison de string est couteuse en performance et mettre ça dans un boucle, j'en parle même pas. Pourquoi pas un int ou un enum ?
    * quelle idée de parcourir tout ton vecteur à chaque affichage, ça va également tuer les performances. Ce que tu peux éviter facilement en ajoutant un "current animation" dans ta structure :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class animationsVector {
        using internalVector = vector<Animation>;
        using internalIterator = internalVector::const_iterator;
        internalVector animations;
        internalIterator currentAnimation;
     
    public:
        void update() { 
            ++currentAnimation;
            if (currentAnimation == end(animations)) 
                currentAnimation = begin(animations);
        }
    };

  17. #17
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    Citation Envoyé par gbdivers Voir le message
    Salut

    Ca me semble mieux a priori de rendre un service plutôt que d'avoir un accesseur.

    Sans avoir lu le reste, ton code m'étonne :
    * si currentAnimationName et a.name sont des string, c'est une mauvaise idée. La comparaison de string est couteuse en performance et mettre ça dans un boucle, j'en parle même pas. Pourquoi pas un int ou un enum ?
    * quelle idée de parcourir tout ton vecteur à chaque affichage, ça va également tuer les performances. Ce que tu peux éviter facilement en ajoutant un "current animation" dans ta structure :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class animationsVector {
        using internalVector = vector<Animation>;
        using internalIterator = internalVector::const_iterator;
        internalVector animations;
        internalIterator currentAnimation;
     
    public:
        void update() { 
            ++currentAnimation;
            if (currentAnimation == end(animations)) 
                currentAnimation = begin(animations);
        }
    };
    C'est vrai que pour les traitements internes ce serait mieux. J'étais dans l'optique de tout faire par nom d'animation pour que l'utilisateur puisse manipuler simplement ses différents éléments. Mais c'est vrai que pour ce qui est des traitement internes, ça coûte pour rien. Je vais changer cela, merci ^^

    je ne connais pas cette utilisation de using. Quelle différence avec un typedef ? et pour les begin et end ? Comment cela fonctionne ?

    Enfin, est-ce qu'un pointeur sur l'animation courante suffirait ? Ou cela reste mieux de passer par un itérateur ?

    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
     
            protected :
     
                ////////////////////////////////////////////////////////////
                /// \brief Move the eye on the board, for the animation \a anim
                ///
                /// \param anim The animation to update
                ///
                ////////////////////////////////////////////////////////////
                void moveEye(Animation& anim);
     
                ////////////////////////////////////////////////////////////
                // Member data
                ////////////////////////////////////////////////////////////
     
                std::vector<Animation> animationsVector; ///< Vector of all the animations of the animHandler.
                sf::Texture* board;                      ///< Board used for all the animations.
                sf::IntRect eye;                         ///< The eye used to move into the board and target a sprite.
                //std::string currentAnimationName;        ///< The name of the current animation
               //je pensais à cela
               Animation* currentAnimation;
    Nullius in verba

  18. #18
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Pour using, c'est une nouvelle syntaxe du C++11, initialement pour les alias de template, mais qui peut être (doit ?) utilisé plus généralement (typedef bientôt déprécié ?). Voir une discussion récente : http://www.developpez.net/forums/d12...1/#post6951685

    Pourquoi un pointeur plutôt qu'un itérateur ? Les conteneurs standard utilisent les itérateurs, ce qui veut dire que tu devras faire une conversion, quel est l'intérêt ?

    Je sais pas si tu implémentes le COW ou équivalent, mais sinon j'aurais plus vu une sémantique d'entité pour ça. Tu n'as pas des copies inutiles avec cette syntaxe ?

    (sinon, HS, mais pour les sprites, on utilise souvent 1 image pour tous les sprites au lieu d'une image par sprite, c'est beaucoup plus performant)

  19. #19
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    En fait c'est pour simplifier mon code, avec l'inférence de type et les lambda, on peut obtenir directement une référence sur une animation (je suppose que la conversion est faite automatiquement dans ce cas), je trouve ça plus sympa que de manipuler les itérateurs. Mais ouai en fait je sais pas (le problème c'est que j'ai pas touché à mon code depuis vendredi et que je l'ai pas commité (donc là je suis coincé au boulot sans mon code...)). Tu as peut-être raison.

    Pour les copies, je ne peux pas t'affirmer que j'en ai pas une seule qui traine par ci par là, mais je ne penses pas non, justement parce que je parcours toujours le vector avec les range-based for et l'inférence de type auto& (et que la création de l'animation (appel au constructeur) se fait dans le push_back directement). Et non pour le COW je ne connais pas. Ma classe Animation est a sémantique d'entité (avec le nom de l'animation unique). Mais pour te rassurer, je me suis demandé une bonne cinquentaine de fois pourquoi c'était le seul vetor de toute ma lib à contenir des objets plutôt que des pointeurs, et ça m'a fait peur plus d'une fois pour ce qui est des copies.

    Pour l'image, j'utilise une seule image pour tous les sprites. Pourquoi tu dis ça ? (qu'est-ce que j'ai encore fait comme bourde )

    Edit : ce topic me donne l'impression qu'il faut que j'arrête de coder la nuit et que je dorme plus...

    Edit2 : il me semble me souvenir que j'avais pris cette décision car la quantité d'animations générées pour une seule image peuvent être énormes, et qu'une bonne quantité de gestionnaire d'animation (qui sont aussi à sémantique d'entité (un seul gestionnaire par objet animable)) sont nécessaire dans un jeu assez poussé. Je crois que je voulais éviter les new autant que possible... mauvais choix ?



    Edit3 : aux temps pour moi, je viens de récupérer mon code entre midi et deux et j'avais déjà fais le changement :
    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
     
    ////////////////////////////////////////////////////////////
    //
    // SFE - Simple and Fast Extensions for SFML
    // Copyright (C) 2012-2013 Clement Fauconnier (cfauconnier86@gmail.com)
    //
    // This software is provided 'as-is', without any express or implied warranty.
    // In no event will the authors be held liable for any damages arising from the use of this software.
    //
    // Permission is granted to anyone to use this software for any purpose,
    // including commercial applications, and to alter it and redistribute it freely,
    // subject to the following restrictions:
    //
    // 1. The origin of this software must not be misrepresented;
    //    you must not claim that you wrote the original software.
    //    If you use this software in a product, an acknowledgment
    //    in the product documentation would be appreciated but is not required.
    //
    // 2. Altered source versions must be plainly marked as such,
    //    and must not be misrepresented as being the original software.
    //
    // 3. This notice may not be removed or altered from any source distribution.
    //
    ////////////////////////////////////////////////////////////
     
    #ifndef SFE_ANIMHANDLER_HPP
    #define SFE_ANIMHANDLER_HPP
     
    ////////////////////////////////////////////////////////////
    // Headers
    ////////////////////////////////////////////////////////////
    #include <SFE/Animation.hpp>
    #include <SFML/Graphics.hpp>
    #include <vector>
    #include <string>
     
    namespace sfe
    {
        ////////////////////////////////////////////////////////////
        /// \brief An animation Handler to manage all the animations
        ///        of a single animated entity
        ///
        ////////////////////////////////////////////////////////////
        class AnimHandler
        {
            public :
     
                ////////////////////////////////////////////////////////////
                /// \brief Create an animHandler
                ///
                /// \param filename  Directory of the file used for the board
                /// \param eyeWidth  Width of the eye used to cut the board.
                ///                  Defaulting to 32 pixels.
                /// \param eyeHeight Height of the eye used to cut the board.
                ///                  If not defined, eyeWidth is used
                ///
                ////////////////////////////////////////////////////////////
                AnimHandler(const std::string& filename, const int eyeWidth = 32, const int eyeHeight = -1);
     
                ////////////////////////////////////////////////////////////
                /// \brief Destroy the animHandler
                ///
                ////////////////////////////////////////////////////////////
                ~AnimHandler();
     
                ////////////////////////////////////////////////////////////
                /// \brief Play the animation called \a name
                ///
                /// \param name Name of the animation
                ///
                /// @pre Animation must exist. If not, a message will be
                ///      displayed on the error standard, to warn users that
                ///      an error occured, but no exception will be thrown,
                ///      so it is to user repsonsability to handle error cases
                ///
                /// Be careful, because of AnimHandler nature (single animated entity),
                /// only the last animation played will be drawable on a renderTarget.
                ///
                ////////////////////////////////////////////////////////////
                void play(const std::string& name);
     
                ////////////////////////////////////////////////////////////
                /// \brief Add an animation to the animHandler
                ///
                /// \param name          Name of the animation
                /// \param rowPosition   Row on the board to use with (begin at 0).
                /// \param spritesNumber Number of sprites wich compose the animation
                /// \param frequency     Frame Rate of the animation (img/s). Defaulting to NTSC
                ///
                /// \see sfe::Animation
                ///
                ////////////////////////////////////////////////////////////
                void newAnimation(const std::string& name, const int rowPosition, const int spritesNumber, const int frequency = 30);
     
                ////////////////////////////////////////////////////////////
                /// \brief Draw the current animation to a render target
                ///
                /// \param target Render target to draw to
                ///
                /// @pre If no texture has been set to the board, SFML will
                ///      display a white shape of the size of the eye instead.
                ///
                ////////////////////////////////////////////////////////////
                void draw(sf::RenderTarget& target) const;
     
     
                ////////////////////////////////////////////////////////////
                /// \brief Get the current animation of the animHandler
                ///
                /// \return The current animation, wich is the last played.
                ///         If none has been played, returns the first one
                ///         added to the animHandler. If no animation exist,
                ///         return a nullptr.
                ///
                ////////////////////////////////////////////////////////////
                Animation* getCurrentAnimation();
     
                ////////////////////////////////////////////////////////////
                /// \brief Get the animation named \a name
                ///
                /// @pre Animation must exist. If not, a message will be displayed
                ///      to warn users that an error occured, but no exception
                ///      will be thrown. It is user responsability to handle error cases.
                ///
                /// \return The animation named \a name, if exists. If not,
                ///         return a nullptr.
                ///
                ////////////////////////////////////////////////////////////
                Animation* getAnimation(const std::string& name);
     
            protected :
     
                ////////////////////////////////////////////////////////////
                /// \brief Move the eye on the board, for the animation \a anim
                ///
                /// \param anim The animation to update
                ///
                ////////////////////////////////////////////////////////////
                void moveEye(Animation& anim);
     
                ////////////////////////////////////////////////////////////
                // Member data
                ////////////////////////////////////////////////////////////
     
                std::vector<Animation*> animationsVector; ///< Vector of all the animations of the animHandler.
                sf::Texture* board;                      ///< Board used for all the animations.
                sf::IntRect eye;                         ///< The eye used to move into the board and target a sprite.            
                std::string currentAnimationName;        ///< The name of the current animation
        };
     
    } // namespace sfe
     
    #endif // SFE_ANIMHANDLER_HPP
     
    ////////////////////////////////////////////////////////////
    /// \class sfe::AnimHandler
    /// \ingroup anims
    ///
    /// sfe:AnimHandler is a class that allows to easily
    /// manage a single animated entity, that can be drawn on a render target.
    ///
    /// sfe::AnimHandler works in combination with the sfe::Animation class and.
    /// the sfe::Catalog static class.
    ///
    /// sfe::AnimHandler can be used with the Catalog, but can also be an attribute
    /// to another class, like a "MyCharacter" class for example.
    ///
    /// Usage example:
    /// \code
    ///
    /// // Declare AnimHandler with a size of 32*32 pixels
    /// sfe::AnimHandler Toto("Toto.png");
    ///
    /// // Declare an animHandler for animations with size 64*64 pixels
    /// sfe::AnimHandler Titi("Titi.png", 64);
    ///
    /// // Declare an animHandler with 79*119 pixels
    /// sfe::AnimHandler Tata("Tata.png", 79, 119);
    ///
    /// // Create animations and add them to the animHandlers
    /// Toto.newAnimation("Idle Left", 0, 3);
    /// Toto.newAnimation("walk left", 1, 3);
    /// Titi.newAnimation("Jump", 11, 17);
    /// Titi.NewAnimation("Danse", 12, 24);
    ///
    /// // Add the animHandler Toto to the Catalog
    /// sfe::Catalog::add(Toto, "Toto");
    ///
    /// // [...]
    /// bool JumpHasBeenPressed = false;
    ///
    /// // Handle events
    /// if (event.type == sf::Event::KeyPressed)
    /// {
    ///    if (event.key.code == sf::Keyboard::Space)
    ///    {
    ///       JumpHasBeenPressed = true;
    ///    }
    /// }
    ///
    /// // [...]
    ///
    /// if (JumpHasBeenPressed)
    /// {
    ///    someMethodToHandleJump();
    ///    Titi.Play("Jump");
    /// }
    ///
    /// // Draw it
    /// Toto.draw(window);
    /// Titi.draw(window);
    ///
    /// // This will be ignored, because no animation exists for this entity.
    /// // A message will be displayed on the standard error to warn user that
    /// // an error occured.
    /// Tata.draw(window);
    /// \endcode
    ///
    /// \see sfe::Animations
    ///
    ////////////////////////////////////////////////////////////
    Je vais effectuer la correction que tu m'as suggéré, et je me permets de poster ma classe entière pour voir si tu (ou d'autres, comme mon anglais par exemple ) n'aurait pas d'autres suggestions sur mes méthodes, et tout le reste (on ne cesse jamais s'améliorer c'est énervant à la longue )
    Nullius in verba

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

Discussions similaires

  1. Référence comme type de retour
    Par oodini dans le forum C++
    Réponses: 6
    Dernier message: 10/02/2011, 17h18
  2. Manipuler des fichiers de type Unix sous Windows
    Par hermes1983 dans le forum Entrée/Sortie
    Réponses: 4
    Dernier message: 06/06/2009, 08h43
  3. Comment manipuler des instance de type Date java.sql
    Par mehdi_scofield dans le forum Langage
    Réponses: 3
    Dernier message: 29/10/2008, 16h15
  4. Quel langage pour manipuler des entiers très longs ?
    Par mis_dj dans le forum Langages de programmation
    Réponses: 8
    Dernier message: 10/05/2006, 21h12
  5. reflexion et type de retour des méthodes
    Par money mark dans le forum Langage
    Réponses: 2
    Dernier message: 09/04/2006, 18h46

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