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é :
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.
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; }
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
le memmove est la pour gérer le swap d'un objet sur lui même.
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)); }
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
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.
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; ... }
Méthode 3 : On créé des méthodes privées qui nous permettent de swapper 2 objets
La dans l'idée ca me plait assez mais en fait je suis obligé de faire du bricolage pour y parvenir :
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; }
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
Partager