• [^] # Re: Très rapide review

    Posté par (site web personnel) . En réponse au journal Petit Framework de jeu 2d en C++. Évalué à 5.

    Comment sait-on si l'object est "un peu gros" à part faire un benchmark ?

    Je vais plutôt répondre à : Quand passer un objet par référence constante plutôt que par valeur (recopie) ?

    La réponse rapide : Si l'objet n'est pas modifié: tout le temps. Sinon, passage par adresse (pas par référence).

    La réponse longue :

    Un passage par référence coute la même chose qu'un passage par adresse : la copie de l’adresse de l'objet (4 octets en 32 bits, 8 en 64 bits). D'un point de vu mémoire, un objet faisant très souvent plus de 4 octets, il doit donc quasiment tout le temps être passé par référence.

    De plus la recopie d'un objet (même petit) n'est pas obligatoirement gratuite. Le constructeur par recopie peut faire des opérations relativement longue. Un passage par référence évite la recopie.

    Une recopie perd le "type réel" de l'objet et casse le polymorphisme:

    #include <iostream>
    struct Obj
    {
     virtual int getvalue() const { return 1; }
    };
    struct Obj2: public Obj
    {
     virtual int getvalue() const { return 2; }
    };
    void test1(const Obj toto)
    {
     std::cout << "test1 " << toto.getvalue() << std::endl;
    }
    void test2(const Obj& toto)
    {
     std::cout << "test2 " << toto.getvalue() << std::endl;
    }
    int main()
    {
     Obj2 toto;
     test1(toto); // affiche "test1 1"
     test2(toto); // affiche "test2 2"
     return 0;
    }

    Le cassage du polymorphisme peut être voulu, mais ça surprendra probablement l'utilisateur. Et je conseille un appelle explicite à la méthode d'origine si c'est voulu : "toto.Obj::getvalue()"

    Par contre, je déconseille très fortement le passage par référence non constante:

    • À la lecture d'un code déjà écrit, impossible de savoir si l'objet sera modifié par la fonction sans aller voir la définition de celle-ci. Si une fonction modifie un argument, c'est passage par adresse. point. Au moins c'est clair (à la lecture) : je passe l'objet=>pas de modif, je passe l'adresse => modif.
    • Impossible de passer des objets temporaires. Ce code ne compile pas :
    struct Obj
    {
     int getvalue() const { return 1; }
    };
    void test(Obj& toto)
    {
     std::cout << toto.getvalue() << std::endl;
    }
    int main()
    {
     test(Obj());
     return 0;
    }

    Avec "void test(const Obj& toto)" ça compile.

    Matthieu Gautier|irc:starmad