Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Pérennisation/serialisation de pointeurs

12 réponses
Avatar
Dominique MICOLLET
Bonjour,

La question est sans doute archi-classique, mais je n'ai pas réussi à
trouver une réponse qui me satisfasse : je n'ai pas du employer les bons
mots clef. Si tel est bien le cas, veuillez me renvoyer au fameux manuel
adéquat.

Soit deux classes :
class A
{
.....
}

class B
{
class A * C;
.....
}


Je dois (1), en fin d'un programme, enregistrer dans un fichier les
différents objets de classe B, en conservant d'une manière ou d'une autre
le lien vers l'objet pointé de classe A.
Il est évident qu'enregistrer l'adresse est une absurdité, puisqu'à la
relecture dans un autre programme, les objets de la classe A ne seront pas
recréés à la même adresse.

La seule solution qui me vienne à l'esprit est d'enrichir la classe A d'une
clef numérique et d'enregistrer pour chaque objet de B la valeur de la
clef de l'objet A pointé. Je suis conscient que la relecture des fichiers
va être lourde.

Auriez-vous d'autres suggestions à me faire ?

Cordialement.


(1) Il s'agit de programmes de calcul scientifique à long temps de
traitement qui nécessitent, entre autres, des points de reprise en cas
d'arrêt intempestif des machines ou des exécutions avec des paramètres
variables à partir d'un jeu commun de données intermédiaires.

--
Dominique MICOLLET
Adresse email : enlever deux francs

10 réponses

1 2
Avatar
Alain Ketterlin
Dominique MICOLLET writes:

Soit deux classes :
class A
{
.....
}

class B
{
class A * C;
.....
}



Ca veut dire que B contient un membre nommé C qui est un pointeur vers
A, c'est cela ?

Je dois (1), en fin d'un programme, enregistrer dans un fichier les
différents objets de classe B, en conservant d'une manière ou d 'une autre
le lien vers l'objet pointé de classe A.
Il est évident qu'enregistrer l'adresse est une absurdité, puis qu'à la
relecture dans un autre programme, les objets de la classe A ne seront pas
recréés à la même adresse.

La seule solution qui me vienne à l'esprit est d'enrichir la classe A d'une
clef numérique et d'enregistrer pour chaque objet de B la valeur de la
clef de l'objet A pointé. Je suis conscient que la relecture des fic hiers
va être lourde.



En fait, il n'est pas nécessaire de conserver ce champ dans les object s,
puisque tu en as besoin uniquement à l'écriture, et que tu peux
reconstruire ce qu'il faut pour la lecture. En gros :

- pendant l'écriture tu conserves une (ou deux) map<A*,int> : chaque
écriture d'un A commence par un entier, que tu mets dans la table
- quand tu écris un B, tu écris l'entier associé au A point é
- pendant la lecture postérieure, tu conserves une table map<int,A*> :
chaque lecture d'un A obtient l'entier, alloue l'objet, et ajoute une
entrée dans la table
- quand tu lis un B, tu lis l'entier et tu consultes la table pour
obtenir le pointeur

C'est une version naïve, mais je n'ai jamais eu besoin d'autre chose. Tu
peux avoir une table par classe ou une globale et utiliser des casts,
etc. Ca permet de sauvegarder des graphes d'objets acyclique (en testant
l'existence avant de réallouer), et ça s'étend assez facilem ent à des
graphes quelconques.

-- Alain.
Avatar
pasdespam
Dominique MICOLLET wrote:

Bonjour,

La question est sans doute archi-classique, mais je n'ai pas réussi à
trouver une réponse qui me satisfasse : je n'ai pas du employer les bons
mots clef. Si tel est bien le cas, veuillez me renvoyer au fameux manuel
adéquat.

Soit deux classes :
class A
{
.....
}

class B
{
class A * C;
.....
}


Je dois (1), en fin d'un programme, enregistrer dans un fichier les
différents objets de classe B, en conservant d'une manière ou d'une autre
le lien vers l'objet pointé de classe A.
Il est évident qu'enregistrer l'adresse est une absurdité, puisqu'à la
relecture dans un autre programme, les objets de la classe A ne seront pas
recréés à la même adresse.

La seule solution qui me vienne à l'esprit est d'enrichir la classe A d'une
clef numérique et d'enregistrer pour chaque objet de B la valeur de la
clef de l'objet A pointé. Je suis conscient que la relecture des fichiers
va être lourde.

Auriez-vous d'autres suggestions à me faire ?

Cordialement.


(1) Il s'agit de programmes de calcul scientifique à long temps de
traitement qui nécessitent, entre autres, des points de reprise en cas
d'arrêt intempestif des machines ou des exécutions avec des paramètres
variables à partir d'un jeu commun de données intermédiaires.



ton idee est bonne avec une table de hachage
Avatar
Fabien LE LEZ
On Fri, 29 Oct 2010 09:49:42 +0200, Dominique MICOLLET
:

(1) Il s'agit de programmes de calcul scientifique à long temps de
traitement qui nécessitent, entre autres, des points de reprise en cas
d'arrêt intempestif des machines ou des exécutions avec des paramètres
variables à partir d'un jeu commun de données intermédiaires.



Tu as grosso modo le choix entre deux méthodes.

La méthode propre serait une vraie sérialisation. Le format des
données dans le fichier est indépendant du format en mémoire.
Tu recrées tes objets à partir des données ; ton problème de pointeur
disparaît donc.
Avantage : c'est élégant et portable ; les données sont lisibles même
après recompilation du programme, ou sur une machine totalement
différente.

Si la solution propre est trop lente pour tes besoins, tu peux décider
de te contenter d'une solution crade : copie directe d'une partie de
la RAM dans un fichier (façon mmap()).

Une fois que tu as décidé d'utiliser cette solution et d'en accepter
les conséquences, tu peux y aller franco.

Par exemple, une solution serait d'allouer un gros bloc de RAM au
début de la première exécution du programme, et de créer tes objets
là-dedans (avec un allocateur maison). Tu enregistres alors ce gros
bloc (ou, du moins, la partie utilisée) dans un fichier.
Lors de la deuxième exécution, tu lis le gros bloc de mémoire depuis
le fichier.
De deux choses l'une :
- Soit tu peux allouer le bloc de mémoire toujours à la même
adresse. Je ne sais pas comment faire, mais ça m'étonnerait qu'un
noyau récent ne propose pas ce genre d'option. Dans ce cas, ton
problème est réglé : tous tes objets restent aux mêmes adresses.
- Soit tu n'y arrives pas. Dans ce cas, tous tes objets ont la
même position relative. Il faut calculer l'offset entre la position du
bloc en mémoire lors de la deuxième exécution et la position du bloc
en mémoire lors de la première exécution, et ajouter cet offset à tous
tes pointeurs.
Avatar
Lucas Levrel
Le 29 octobre 2010, Dominique MICOLLET a écrit :

Soit deux classes :
class A
{
.....
}

class B
{
class A * C;
.....
}


Je dois (1), en fin d'un programme, enregistrer dans un fichier les
différents objets de classe B, en conservant d'une manière ou d'une autre
le lien vers l'objet pointé de classe A.



S'il y a peu d'instances d'A tu pourrais faire un fichier pour chacune.

Tu pourrais aussi grouper les B par instance d'A commune, et sauver les A
sous forme de commentaires en tête de chaque groupe. Par exemple, si :
B1.C=&A1
B2.C=&A2
B3.C=&A1
tu enregistrerais :
# A1
B1
B3
# A2
B2
mais là ça dépend carrément du contenu d'A et B !

--
LL
Avatar
FX
Dominique MICOLLET a écrit :
Je dois (1), en fin d'un programme, enregistrer dans un fichier les
différents objets de classe B, en conservant d'une manière ou d'une autre
le lien vers l'objet pointé de classe A.
Il est évident qu'enregistrer l'adresse est une absurdité, puisqu'à la
relecture dans un autre programme, les objets de la classe A ne seront pas
recréés à la même adresse.



Je rajouterai juste une chose par rapport aux réponse déjà apportées :
c'est le cas où les objets A sont uniques. C'est-à-dire si 2 objets B ne
peuvent pas pointés sur le même A, ce qui simplifie le problème. C'est
bête, mais rien n'a été précisé là-dessus.

Dans ce cas, il suffit de restaurer les nouvelles valeurs des pointeurs
après relecture. Et il n'y a pas bien mieux, dans le cas général, que
d'itérer sur tous les B créés pour modifier la valeur du pointeur (en
dehors de la suggestion de Fabien Le Lez, mais personnellement, elle me
paraît plutôt compliquée et problématique).

Après, il y a peut-être une meilleure solution pour ton problème précis,
mais on n'a pas assez d'éléments pour juger.
Avatar
James Kanze
On Oct 29, 10:10 am, Fabien LE LEZ wrote:
On Fri, 29 Oct 2010 09:49:42 +0200, Dominique MICOLLET
:

>(1) Il s'agit de programmes de calcul scientifique à long
>temps de traitement qui nécessitent, entre autres, des points
>de reprise en cas d'arrêt intempestif des machines ou des
>exécutions avec des paramètres variables à partir d'un jeu
>commun de données intermédiaires.

Tu as grosso modo le choix entre deux méthodes.

La méthode propre serait une vraie sérialisation. Le format
des données dans le fichier est indépendant du format en
mémoire. Tu recrées tes objets à partir des données ; ton
problème de pointeur disparaît donc.



Pas vraiment. Si les A font en fait logiquement partie des B, ça
peut marcher, mais sinon, tu as toujours le problème d'étabilir
les liens. (La suggestion précédante, de numéroter des A au fur
et à mésure qu'on les rencontre, avec un map<A*, int>, me semble
bien la solution qui convient le plus.)

--
James Kanze
Avatar
Dominique MICOLLET
Alain Ketterlin wrote:

Ca veut dire que B contient un membre nommé C qui est un pointeur vers
A, c'est cela ?



Oui.

C'est une version naïve, mais je n'ai jamais eu besoin d'autre chose.



Ça l'air de parfaitement me convenir. Je ne connaissais pas map<..>.

Tu peux avoir une table par classe ..



Dans l'hypothèse ou je n'aurais qu'un table par classe, vous semblerait-il
hérétique d'en faire un membre statique de ladite classe, ce qui
permettrait à un objet de fournir lui-même son numéro (et incidemment de
connaître n'importe lequel de ses frères) ?

Merci pour le conseil.

Cordialement.
--
Dominique MICOLLET
Adresse email : enlever deux francs
Avatar
Dominique MICOLLET
Dominique MICOLLET wrote:

Bonjour,


....
Auriez-vous d'autres suggestions à me faire ?



Merci à tous les contributeurs pour leurs suggestions.

Celle qui me semble la plus simple pour moi est la mise en ½uvre de map<..>
juste au moment de l'écriture et temporairement à la lecture.
J'envisagerai l'emploi d'une table de hachage (1) si la quantité de données
est importante au point de ralentir la lecture de manière rédhibitoire.

A priori deux B pourraient partager le même A, et donc la solution
d'intégrer directement l'écriture de A dans celle de B est sans doute
compromise : il faut cependant que j'affine l'analyse pour m'en assurer.

Quand à l'utilisation de mmap et consort, ça me parait trop risqué et peu
portable (il se peut que le programme ait a tourner sur Mac, alors qu'il
est écrit sur PC).

Quoi qu'il en soit merci pour vos conseils.


PS : ça serait plus rigolo de l'appeler un hachis, mais pour une fois je
vais suivre la terminologie consacrée :-)
--
Dominique MICOLLET
Adresse email : enlever deux francs
Avatar
Alain Ketterlin
Dominique MICOLLET writes:

[...]
Tu peux avoir une table par classe ..



Dans l'hypothèse ou je n'aurais qu'un table par classe, vous
semblerait-il hérétique d'en faire un membre statique de ladite
classe, ce qui permettrait à un objet de fournir lui-même son n uméro
(et incidemment de connaître n'importe lequel de ses frères) ?



Hérétique est peut-être un peu fort... Cela dit, la table de traduction
n'est utile qu'au moment de la sérialisation, ce n'est donc pas la pei ne
de la conserver. Si tes objets fournissent un identificateur unique,
fais-en une fonction membre, et utilise cette fonction pour attribuer
les "numéros" (note que tu peux utiliser la valeur de l'adresse si tu
veux -- il faut juste que l'ensemble des identificateurs soit cohérent
au moment de la sérialisation). Bien sûr, si tu comptes te servir de la
table de correspondance pour autre chose, tu peux la conserver.

Quant à une table de hachage, dans mon expérience, ça vaut l e coup si on
est sûr de sa fonction de hachage (oui je sais, j'enfonce une porte
ouverte, mais c'est très important pour l'efficacité). Dans les a utres
cas, map<,> fonctionne très bien (dans l'implémentation que j'uti lise,
celle de gcc, map<,> repose sur des arbres red-black et utilise less<>
pour l'ordre des clés). En gros, il faut choisir entre une complexit é
logarithmique garantie avec map<,> et une complexité constante avec une
bonne fonction de hachage mais quasi-linéaire avec une mauvaise.

-- Alain.
Avatar
Fabien LE LEZ
On Fri, 29 Oct 2010 09:49:42 +0200, Dominique MICOLLET :

class B
{
class A * C;



Tes objets de classe A, tu dois bien les stocker quelque part.
Une idée serait de les stocker dans un std::vector<> (ou
éventuellement std::deque<>), et de mettre dans chaque B, non pas un
pointeur vers le A, mais l'index du A dans le tableau.
Bien sûr, ça ne fonctionne que si ta liste de A est relativement fixe.
1 2