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 :

optimisation du swap d'objets à contenu dynamique


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre chevronné
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    399
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 399
    Par défaut optimisation du swap d'objets à contenu dynamique
    Bonjour, j'aimerai optimiser le swap d'objets de classe contenant un tableau dynamique.

    Comme la taille du tableau n'est connu qu'a la création de l'objet et que le tableau n'appartient qu'a l'objet et ne peux pas être partagé, j'ai redéfini le contructeur par copie et l'opérateur d'assignation. Le destructeur libère le tableau.

    swapper de tels objets avec un swap classique n'est pas du tout optimisé :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    swap(A& a,A& b)
    {
        A tmp(a);
        a = b;
        b = tmp;
    }
    On va avoir 3 créations de tableaux et 3 destructions, plus 3 copies des éléments du tableau. J'ai fait une petite opti pour l'assignation et la copie qui ne realloue pas le tableau si le nouveau tableau est de même taille que l'ancien, cela se contente de copier les éléments un a un. Donc pour un swap entre 2 objets contenant un tableau de même taille, on va avoir quand même 1 création, 1 destruction et 3 copies des éléments.

    Or toutes ces opérations ne sont pas necessaires dans le cas du swap, car il suffit de permutter les 2 pointeurs vers le tableau.

    J'ai donc testé et benché 3 méthodes qui ne me plaisent en fait que moyennement :

    Méthode 1 : A la barbare on swap les blocs mémoire des objets
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    swap(A& a,A& b)
    {
        char* tmp[sizeof(A)];
        memcpy(tmp,&a,sizeof(A));
        memmove(&a,&b,sizeof(A));
        memcpy(&b,tmp,sizeof(A));
    }
    le memmove est la pour gérer le swap d'un objet sur lui même.
    Je ne pense pas que les memcpy soient particulièrement adapté a des petits blocs de mémoire. Je ne sais pas pourquoi mais j'aime pas trop cette méthode

    Méthode 2 : On swap 1 à 1 chacun des paramètres de la classe
    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
     
    swap(A& a,A& b)
    {
        type1 TMPparam1 = a.param1;
        type2 TMPparam2 = a.param2;
        ...
     
        type1 a.param1 = b.param1;
        type2 a.param2 = b.param2;
        ...
     
        type1 b.param1 = TMPparam1;
        type2 b.param2 = TMPparam2;
        ...
    }
    La ca me plait pas parceque c'est très lourd a écrire et pas très élégant(surtout s'il y a beacoup de paramètre) et puis si on en rajoute, il faut modifier la fonction.

    Méthode 3 : On créé des méthodes privées qui nous permettent de swapper 2 objets
    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
     
    class A
    {
    private :
     
        A(bool nothing);
        void copy(const A& a);
    }
     
    A::A(bool nothing){}
     
    void A::copy(const A& a);
    {
        param1 = a.param1;
        param2 = a.param2;
        ...
    }
     
    swap(A& a,A& b)
    {
        A tmp(false);
        tmp.copy(b);
        a.copy(b);
        b.copy(tmp);
        tmp.t = NULL;
    }
    La dans l'idée ca me plait assez mais en fait je suis obligé de faire du bricolage pour y parvenir :
    Créer un constructeur privée qui fait rien avec un paramètre bidon qui sert a rien pour le différencier des autres. (dans le but d'éviter la création originelle du tableau)
    Mettre le tableau de tmp a NULL a la fin pour éviter qu'il soit détruit (car il pointe sur le tableau qui est maintenant celui de b) par le destructeur de tmp lorsque l'on sort du swap.

    Bref je n'arrive pas a trouver une méthode élégante pour faire ce que je veux faire. Je précise que cette classe n'est pas destiner a être dérivée.

    J'ai fait quelques tests de performances sur un très grand nombre de swap entre 2 objets. En gros ca donne ca (j'ai plus les chiffre sous les yeux) :

    classique : 5000 ms
    methode 1 : 170 ms
    méthode 2 : 80 ms
    méthode 3 : 130 ms


    Par contre parfois en fonction des générations (il faut regénéraer le projet pour que ca arrive), j'avais ce genre de résultats :

    classique : 5000 ms
    methode 1 : 170 ms
    méthode 2 : 1300 ms
    méthode 3 : 1500 ms


    Je ne sais pas du tout a quoi c'est du, quelqu un a une idée ?
    Pour l'instant j'ai choisi la méthode 1 (swap de blocs mémoire) parce c'est la moins "bricolage" et qu'il n'y a pas le problème avec les résultats variables que je ne comprend pas du tout même si ce n'est pas la plus rapide. Mais je pense qu'il y a mieux a faire. Vous auriez des conseils / idées a ce propos. Merci
    SPARK
    Moteur de particule C++ opensource avec modules de rendu OpenGL, Irrlicht et SFML

  2. #2
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    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 296
    Par défaut
    L'opérateur d'affectation devrait être défini à l'aide du swap, et non le contraire.
    Quand à std::swap, définis-le à partir d'une fonction membre de swap qui sait très précisément déplacer ce qu'il faut. (C'est l'approche retenue dans la SL)
    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...

  3. #3
    Membre chevronné
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    399
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 399
    Par défaut
    Citation Envoyé par Luc Hermitte Voir le message
    L'opérateur d'affectation devrait être défini à l'aide du swap, et non le contraire.)
    Je ne comprend pas exactement

    Citation Envoyé par Luc Hermitte Voir le message
    Quand à std::swap, définis-le à partir d'une fonction membre de swap qui sait très précisément déplacer ce qu'il faut. (C'est l'approche retenue dans la SL)
    C'est ce que j'ai fait en fait, la spécialisation de std::swap appelle une méthode public de A qui fait ce qui faut faire. J'ai simplifié dans le message parceque ce n'est pas utile a mon problème en soi.
    SPARK
    Moteur de particule C++ opensource avec modules de rendu OpenGL, Irrlicht et SFML

  4. #4
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Normalement, la spécialisation de swap<> sert à l'idiome Non-throwing Swap : Les objets eux-mêmes ne contenant que des pointeurs vers les données, on swappe simplement les pointeurs.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    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 296
    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
    struct T {
        T(T const&);
        ~T() ;
     
        T& operator=(T const& rhs) {
            T tmp(rhs);
            tmp.swap(*this);
            return *this;
        }
     
        void swap(T & other) {
            std::swap(other.m_ptr, this->m_ptr);
        }
    };
    Pour faire plus efficace, il faut limiter le nombre d'éléments à échanger lors du swap (avec un pimpl p.ex.), prendre rhs par copie dans l'opérateur d'affectation, ou attendre le C++0x qui disposera de std::move et autres facilités (rvalue references) améliorant les perfs quand on n'a pas besoin d'une copie complète.
    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...

  6. #6
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        T& operator=(T rhs) {
            rhs.swap(*this);
            return *this;
        }
    est mieux que

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        T& operator=(T const& rhs) {
            T tmp(rhs);
            tmp.swap(*this);
            return *this;
        }

  7. #7
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Enfin de toute façon, si on définit l'opérateur en inline, il y a des chances que les deux donnent le même code assembleur...

    Edit: Ah non, pas forcément pour un objet temporaire:
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    MyClass a;
    a = MyClass(param1, param2);
    Là, il peut y avoir une copie de plus pour le passage par référence...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par Frifron Voir le message
    Je ne comprend pas exactement
    Tu definis ton swap et apres tu utilises
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    C& C::operator=(C other)
    {
       this->swap(other);
       return *this;
    }
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    C& C::operator=(C const& other)
    {
       C(other).swap(*this);
       return *this;
    }
    comme operateur d'assignation.

    Questions subsidiaires pour ceux qui suivent:
    - quelle est la difference entre les deux formes ?
    - pourquoi pas this->swap(C(other)) ?

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

Discussions similaires

  1. [Objet] Représentation dynamique
    Par Mister Nono dans le forum Général JavaScript
    Réponses: 9
    Dernier message: 21/10/2005, 12h38
  2. [POO] detecter un objet créé dynamiquement ...
    Par SpaceFrog dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 10/10/2005, 12h02
  3. Effet visuel de Contenu dynamique
    Par kolib dans le forum ASP
    Réponses: 7
    Dernier message: 12/09/2005, 08h37
  4. Réponses: 2
    Dernier message: 09/09/2005, 10h06
  5. Optimisation du swap sous Fedora Core 2
    Par demeuremichel dans le forum Administration système
    Réponses: 3
    Dernier message: 20/02/2004, 00h52

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