OVH Cloud OVH Cloud

pb de design structure de données

5 réponses
Avatar
Patapouf
Bonjour,

J'ai une classe Cell d=E9finie telle que:

// fichier cell.h
class Cell {
public:
Cell( ... ); // constructeur
Cell(); // constructeur par d=E9faut

~Cell(); // destructeur (d=E9truit aussi represent_)

public:
/* diverses m=E9thodes */

void build_representation( /* arguments */ );

Representation* get_representation() const {
return represent_;
}
private:
/* divers membres */
Representation* represent_;
// represent_ initialis=E9 par le constructeur
// par d=E9faut de Representation
// dans le constructeur de Cell
};

// fin fichier cell.h

La classe Representation impl=E9mente une repr=E9sentation d'un objet
quelconque (=E7a n'est pas l'objet de la question), mais la construction
d'un tel objet est assez lourde (et longue surtout).

Il n'existe "g=E9n=E9ralement" (pour l'instant c'est le cas) qu'une seule
instance d'un Cell. Comme ceci,

// fichier main.cpp
void main() {

/* initialisation de variables */

for( int i =3D 0; i < 10; ++i ) {
Cell* cur_cell =3D new Cell( /* variables */ );
cur_cell->build_representation( /* arguments */ );

/* puis op=E9rations sur cur_cell->get_representation() */

delete cur_cell;
// dans le destructeur, on fait attention aux
// fuites m=E9moires li=E9es =E0 represent_
}
}
// fin fichier main.cpp


Or, il s'av=E9re que la construction du membre represent_ est la m=EAme
pour tous les Cell cr=E9=E9s, =E0 une translation pr=E8s. Donc je ne tire
pas parti de la situation en termes de performances. Car =E0 chaque
it=E9ration je reconstruit un objet Representation qui est le m=EAme que
le pr=E9c=E9dent =E0 une translation pr=E8s.

Mon id=E9e serait de cr=E9er une fois l'objet (lors de la premi=E8re
instanciation d'une classe Cell, representation serait alors static?),
puis d'impl=E9menter une m=E9thode translate_representation( Vector vect
); dans la classe Cell, qui serait appel=E9 =E0 chaque nouvelle
instanciation.

Mes questions sont les suivantes :
1. Comment g=E9rer la m=E9moire?
2. Qui est le propri=E9taire de represent_ alors?
3. Quelles seraient vos id=E9es pour am=E9liorer mes performances?

Merci de vos remarques
Marc

5 réponses

Avatar
Sylvain
Patapouf wrote on 26/04/2006 14:47:

class Cell {
public:
Cell( ... ); // constructeur
Cell(); // constructeur par défaut
~Cell(); // destructeur (détruit aussi represent_)

public:
void build_representation( /* arguments */ );
Representation* get_representation() const {
return represent_;
}
private:
Representation* represent_;
};

La classe Representation implémente une représentation d'un objet
quelconque (ça n'est pas l'objet de la question), mais la construction
d'un tel objet est assez lourde (et longue surtout).


au jeu des devinettes, Cell contient des coordonnées ou une mesure
intensive et Representation 'traduit' visuellement cette ou ces valeurs
(en son, en couleur, en graphe, ...) ou prépare ce rendu en assistant Cell.

for( int i = 0; i < 10; ++i ) {
Cell* cur_cell = new Cell( /* variables */ );
cur_cell->build_representation( /* arguments */ );
/* puis opérations sur cur_cell->get_representation() */
delete cur_cell;
}


Or, il s'avére que la construction du membre represent_ est la même
pour tous les Cell créés, à une translation près.


qui se translate ? les paramètres propres à Cell ? les paramètres
propres à Representation ? ou le désir de l'utilisateur qui demande "la
même représentation de la même cellule" à une translation près ?

Mon idée serait de créer une fois l'objet (lors de la première
instanciation d'une classe Cell, representation serait alors static?),
puis d'implémenter une méthode translate_representation( Vector vect
); dans la classe Cell, qui serait appelé à chaque nouvelle
instanciation.


si Cell est muni de la translation, representation peut rester variable
d'instance car vous crérez alors une seule cell qui construira une seule
repr. (l'unique instance cell sera ensuite translatée).

si plusieurs cells devaient pouvoir être représenter en même temps (un
temps où plusieurs cells coexistent), en effet representation pourrait
être une variable de class (statique) et un mécanisme de reference
counting permettra de la détruire avec le dernier cell -- toutefois
votre exemple ne montre pas cela, il n'y a qu'un seul cell à la fois, le
ref. counting serait caduque et la variable de classe ne pourrait être
libérée par ~cell (mais seulement manuellement).


un autre moyen de voir tout cela est de considérer la representation
comme réellement un 'renderer' indépendant et non plus comme un attribut
opacifié par la cellule; s'il créé (visuellement) la représentation, il
s'alimentera de const cell& qui lui fourniront les paramètres/dimensions
à mettre en forme, s'il participe juste à leur mise en forme
mathématique il sera un operateur au service du renderer final et
recevra de la même facon les cellules une à une pour effectuer la
transformation requise; dans les 2 cas representation devient un outil
(pouvant devenir polymorphique) indépendant des cellules à représenter,
il est plus caractériser par le fait qu'il représente "quelque chose
avec des caractéristiques données" (comme une valeur intensive, ou des
coord. 2D, ou 3D ... ou 11D).

Sylvain.

Avatar
Patapouf
au jeu des devinettes, Cell contient des coordonnées ou une mesure
intensive et Representation 'traduit' visuellement cette ou ces valeurs
(en son, en couleur, en graphe, ...) ou prépare ce rendu en assistant C ell.


Cell contient effectivement un index (une coordonnée dans un maillage
régulier structuré) mais represent_ est un maillage local
(généralement sous forme de tétrahèdres) qui n'est pas utilisé
pour un affichage mais pour des calculs éléments finis


qui se translate ? les paramètres propres à Cell ? les paramètres
propres à Representation ? ou le désir de l'utilisateur qui demande " la
même représentation de la même cellule" à une translation près ?


Dans le main, on crée dans chaque boucle une instance de Cell qui est
détruite à la fin de l'itération. Pour chaque Cell, on crée un
Representation correspondant et on effectue des calculs Elts Finis
dessus. Entre deux Cell, il y a un rapport de translation mais pas
seulement (je parcours les index de la grille structurée). En fonction
de la position de Cell, je récupère un certain nombre d'informations.
Ces opérations sont assez rapides. Sauf pour la création de
represent_, qui est un remaillage local. Seulement il est le même que
le précédent à une translation près.


si Cell est muni de la translation, representation peut rester variable
d'instance car vous crérez alors une seule cell qui construira une seule
repr. (l'unique instance cell sera ensuite translatée).


Munir Cell de la translation une idée qui me plait car la translation
est dans mon cas un fonction implicite et du coup, je peux limiter les
possibiltés de fuites mémoires car je n'ai qu"une instance de Cell et
de Representation.


si plusieurs cells devaient pouvoir être représenter en même temps (un
temps où plusieurs cells coexistent), en effet representation pourrait
être une variable de class (statique) et un mécanisme de reference
counting permettra de la détruire avec le dernier cell -- toutefois
votre exemple ne montre pas cela, il n'y a qu'un seul cell à la fois, le
ref. counting serait caduque et la variable de classe ne pourrait être
libérée par ~cell (mais seulement manuellement).


ok


un autre moyen de voir tout cela est de considérer la representation
comme réellement un 'renderer' indépendant et non plus comme un attri but
opacifié par la cellule; s'il créé (visuellement) la représentati on, il
s'alimentera de const cell& qui lui fourniront les paramètres/dimensions
à mettre en forme, s'il participe juste à leur mise en forme
mathématique il sera un operateur au service du renderer final et
recevra de la même facon les cellules une à une pour effectuer la
transformation requise; dans les 2 cas representation devient un outil
(pouvant devenir polymorphique) indépendant des cellules à représen ter,
il est plus caractériser par le fait qu'il représente "quelque chose
avec des caractéristiques données" (comme une valeur intensive, ou des
coord. 2D, ou 3D ... ou 11D).


Ok, mais en quoi le fait de dissocier les deux ne fera réaliser qu'une
fois la construction d'un Representation?

Avatar
Patapouf
merci au fait!...
Avatar
Sylvain
Patapouf wrote on 26/04/2006 15:54:

Cell contient effectivement un index (une coordonnée dans un maillage
régulier structuré) mais represent_ est un maillage local
(généralement sous forme de tétrahèdres) qui n'est pas utilisé
pour un affichage mais pour des calculs éléments finis

ok (ça me rajeunit pas ce type de calcul).


Entre deux Cell, il y a un rapport de translation mais pas
seulement (je parcours les index de la grille structurée). En fonction
de la position de Cell, je récupère un certain nombre d'informations.
Ces opérations sont assez rapides. Sauf pour la création de
represent_, qui est un remaillage local. Seulement il est le même que
le précédent à une translation près.


yep, si je comprends bien, le remailllage est construit seulement en
fonction de la nouvelle cellule (suffisament et/ou arbritairement large
pour l'englober), si tel est le cas, une solution est de calculer le
maillage complet qui servira à toutes les cellules évaluées - cela
suppose également que le cout/la position de chaque cellule est connue
d'avance, mais je crains que la fameuse translation à reéaliser soit
fonction de l'évaluation précédente - dans ce second cas, il faut peut
être essayer de rendre le maillage "extensible", c'est à dire être
capable de l'étendre dans une ou plusieurs dimensions sans recalculer
les points déjà existants qui feront parti du nouveau maillage.

dans cette esprit c'est la classe Representation qui doit être
translatable, une instance de cette classe existerait indépendemment du
premier cell (au sens relation de classe) mais serait évidemment
calculée pour le représenter, ensuite à chaque itération et en fonction
de la translation nécessaire résultant de l'évaluation de cette cellule,
on reconfigurerait le maillage (suppression de plans inutiles 'hors
limites' et croissance dans les directions nécessaires, si la taille de
ce maillage reste constante vous devriez pouvoir gérer cela via un
déplacement sur l'ensemble des points).

cette instance de Representation serait donc locale à la fonction
principale du calcul (p.e. le main) et donc créé une fois au début,
détruite en sortie.

Sylvain.

Avatar
kanze
Patapouf wrote:

J'ai une classe Cell définie telle que:

// fichier cell.h
class Cell {
public:
Cell( ... ); // constructeur
Cell(); // constructeur par défaut

~Cell(); // destructeur (détruit aussi represent_)

public:
/* diverses méthodes */

void build_representation( /* arguments */ );

Representation* get_representation() const {
return represent_;
}
private:
/* divers membres */
Representation* represent_;
// represent_ initialisé par le constructeur
// par défaut de Representation
// dans le constructeur de Cell
};

// fin fichier cell.h

La classe Representation implémente une représentation d'un
objet quelconque (ça n'est pas l'objet de la question), mais
la construction d'un tel objet est assez lourde (et longue
surtout).

Il n'existe "généralement" (pour l'instant c'est le cas)
qu'une seule instance d'un Cell. Comme ceci,

// fichier main.cpp
void main() {


(Juste en passant, c'est « int main ». « void main » n'est pas
autorisé, et ne passe pas sur beaucoup de compilateurs.

/* initialisation de variables */

for( int i = 0; i < 10; ++i ) {
Cell* cur_cell = new Cell( /* variables */ );
cur_cell->build_representation( /* arguments */ );

/* puis opérations sur cur_cell->get_representation() */

delete cur_cell;
// dans le destructeur, on fait attention aux
// fuites mémoires liées à represent_
}
}
// fin fichier main.cpp

Or, il s'avére que la construction du membre represent_ est la
même pour tous les Cell créés, à une translation près. Donc je
ne tire pas parti de la situation en termes de performances.
Car à chaque itération je reconstruit un objet Representation
qui est le même que le précédent à une translation près.

Mon idée serait de créer une fois l'objet (lors de la première
instanciation d'une classe Cell, representation serait alors
static?), puis d'implémenter une méthode
translate_representation( Vector vect); dans la classe Cell,
qui serait appelé à chaque nouvelle instanciation.

Mes questions sont les suivantes :
1. Comment gérer la mémoire?
2. Qui est le propriétaire de represent_ alors?
3. Quelles seraient vos idées pour améliorer mes performances?


Est-ce qu'il y a une raison pour ne pas faire :

int main()
{
Cell cur_cell ;
for ( int i = 0 ; i < 10 ; ++ i ) {
cur_cell.reinitialize( /* arguments */ ) ;
// ...
}
return EXIT_SUCCESS ;
}

? Ensuite, tu implémentes ta stratégie paresseuse dans Cell, qui
est propriétaire de la mémoire dont il se sert -- à chaque appel
de reinitialize, c'est Cell qui décide s'il faut construire
tout, ou simplement appliquer une transformation simple sur ce
qu'il a déjà. Ça a l'avantage que si le besoin se présente par
la suite, tu peux toujours en avoir deux instances de Cell, et
que toute la gestion de la mémoire, etc. se trouve encapsulée
dans Cell. (Mais il faudrait bien documenter que la première
utilisation de Cell après construction peut être plutôt chère,
et présenter cet idiome comme la façon préférée de s'en servir.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34