OVH Cloud OVH Cloud

class et écriture en mémoire

18 réponses
Avatar
ALB
dans l'exemple suivant,

class point2d {
int x;
int y;
// des methodes
};

point2d A;

peut-on =EAtre s=FBr que les entiers x et y se suivent en
m=E9moire,quelque soit le compileur ? ( a-t-on *(&(A.x)+1) =3D A.y ?)

si, oui :
class point3d : foo {
int z;
// des methodes
};

point3d B;

peut-on =EAtre s=FBr que les entiers x, y et z se suivent en
m=E9moire,quelque soit le compileur ? ( a-t-on *(&(B.x)+2) =3D B.z ?)

ALB

10 réponses

1 2
Avatar
Marc Boyer
Le 13-07-2006, ALB a écrit :
dans l'exemple suivant,

class point2d {
int x;
int y;
// des methodes
};

point2d A;

peut-on être sûr que les entiers x et y se suivent en
mémoire,quelque soit le compileur ? ( a-t-on *(&(A.x)+1) = A.y ?)


Surement pas, vu que c'était déjà faux en C avec les structs.
En C, on était sur d'avoir x avant y mais il peux y avoir
un 'trou' entre (on parle de 'padding' en général).
J'imagine qu'on a la même garantie en C++ par souci
de compatibilité ascendante avec le C.

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. Paul Éluard)

Avatar
Fabien LE LEZ
On 13 Jul 2006 06:09:02 -0700, "ALB" :

class point2d {
int x;
int y;
// des methodes
};

peut-on être sûr


Non.
Je crois qu'on a quelques assurances de ce style (pas forcément
celle-là) quand la classe en question est un POD (i.e. grosso modo une
struct acceptable par un compilateur C).
À partir du moment où il y a des fonctions membres, on n'est sûr de
rien.

Avatar
adebaene
ALB wrote:
dans l'exemple suivant,

class point2d {
int x;
int y;
// des methodes
};

point2d A;

peut-on être sûr que les entiers x et y se suivent en
mémoire,quelque soit le compileur ? ( a-t-on *(&(A.x)+1) = A.y ?)

si, oui :
class point3d : foo {
int z;
// des methodes
};

point3d B;

peut-on être sûr que les entiers x, y et z se suivent en
mémoire,quelque soit le compileur ? ( a-t-on *(&(B.x)+2) = B.z ?)


Non, on n'a pas ces garnaties. Il est généralement possible de les
obtenir avec des extensions spécifiques au compilateur ("#pragma pack"
ou quelque chose de ressemblant), mais c'esr rarement une bonne idée
parce que :
- c'est non portable.
- sur certains processeurs (à peu près tous sauf les x86), il est
impossible de faire des accès mémoire non alignés, donc le
compilaateur est *forcé* d'aligner les variables comme le souhaite le
processeur.
- Sur les processeurs qui acceptent les accès mémoire non alignés,
cela à un impact significatif sur les performances (typiquement, ca
double le temps d'accès à une variable).
- Généralement, quand on veut faire çà, c'est signe d'une mauvaise
conception : on veut mapper une structure sur le contenu binaire d'un
fichier ou d'un flux réseau, ou bien, sur des données déjà
existantes en mémoire. Dans ces cas, la bonne solution consiste à
laisser le compilateur aligner la structure comme il le souhaite et
ajouter des fonctions pour sérialiser/désérialiser la structure
vers/depuis l'autre représentation

Arnaud

Avatar
kanze
Fabien LE LEZ wrote:
On 13 Jul 2006 06:09:02 -0700, "ALB" :

class point2d {
int x;
int y;
// des methodes
};

peut-on être sûr


Non.

Je crois qu'on a quelques assurances de ce style (pas
forcément celle-là) quand la classe en question est un POD
(i.e. grosso modo une struct acceptable par un compilateur C).


Même pas. Comme l'a déjà indiqué Marc, on ne les a même pas en
C.

À partir du moment où il y a des fonctions membres, on n'est
sûr de rien.


L'ajonction des fonctions membres n'empêche pas à une classe
d'être un POD. La présence des membres privés, en revanche, si.

--
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


Avatar
ALB
merci. Au moins, c'est clair et sans appel.

C'est dommage...
En fait, pour mes besoins (gestion de propriétés géométriques),
j'utilise des class à peu près comme je l'ai décris (la 3D herite de
la 2D).

A un moment, je passe à une représentation graphique via OpenGL et je
trouvais dommage de faire des
glVertex3i(pPoint->x,pPoint->y,pPoint->z); si je pouvais avoir
directement accès à un tableau de 3 éléments successifs (histoire
d'economiser des indirections inutiles dans des cas un peu plus
emboités et utiliser glVertex3iv).

ALB
Avatar
Marc Boyer
Le 13-07-2006, ALB a écrit :
A un moment, je passe à une représentation graphique via OpenGL et je
trouvais dommage de faire des
glVertex3i(pPoint->x,pPoint->y,pPoint->z); si je pouvais avoir
directement accès à un tableau de 3 éléments successifs (histoire
d'economiser des indirections inutiles dans des cas un peu plus
emboités et utiliser glVertex3iv).


Il y a bien des moyens de le faire en C++, ie maintenir
les deux chose (x,y,z) + un tableau (ou un vecteur)
ou de ne garder que le tableau/vecteur et de faire
des accesseurs x,y,z, de manière à ce que le tout
soit cohérent, mais au prix d'une surconsommation
mémoire et/ou de CPU.

Je ne pense pas que le jeux en vaille la chandelle.

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. Paul Éluard)

Avatar
Arnaud Meurgues
ALB wrote:

A un moment, je passe à une représentation graphique via OpenGL et je
trouvais dommage de faire des
glVertex3i(pPoint->x,pPoint->y,pPoint->z); si je pouvais avoir
directement accès à un tableau de 3 éléments successifs (histoire
d'economiser des indirections inutiles dans des cas un peu plus
emboités et utiliser glVertex3iv).


Pourquoi ne pas utiliser dans la classe un int[3] ou, mieux, un
vector<int> ?

--
Arnaud

Avatar
ALB

Pourquoi ne pas utiliser dans la classe un int[3] ou, mieux, un
vector<int> ?


je perds alors l'heritage.
A moins qu'il y ait une astuce de vieux sioux ?

Avatar
Marc Boyer
Le 13-07-2006, ALB a écrit :


Pourquoi ne pas utiliser dans la classe un int[3] ou, mieux, un
vector<int> ?


je perds alors l'heritage.
A moins qu'il y ait une astuce de vieux sioux ?


Ce ne serait pas beau, mais on pourrait imaginer (non compilé)

class Point2D {
vector<in> values:
public:
Point2D(): values(2) {};
int& x() {return &(values[0]);}
int& y() {return &(values[1]);}
}

class Point3D: public Point2D {
public:
Point3D() {
assert( values.size() == 2 ); // Mode parano
values.resize(3);
};
int& z() {return &(values[2]);}
}

Mais on perd un peu la sémantique de l'héritage dans le
sens où si on affecte un Point3D à un Point2D, la composante
z reste en mémoire, mais innacessible...

Donc, est-ce que tout cela a un intérêt ? Pas sur...

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. Paul Éluard)


Avatar
Sylvain Togni
A un moment, je passe à une représentation graphique via OpenGL et je
trouvais dommage de faire des
glVertex3i(pPoint->x,pPoint->y,pPoint->z); si je pouvais avoir
directement accès à un tableau de 3 éléments successifs (histoire
d'economiser des indirections inutiles dans des cas un peu plus
emboités et utiliser glVertex3iv).


Reste la solution suivante:

class Point3D
{
public:
Point(int x, int y, int z) {x() = x; y() = y; z() = z}

int const& x() const {return v[0];}
int const& y() const {return v[1];}
int const& z() const {return v[2];}
int& x() {return v[0];}
int& y() {return v[1];}
int& z() {return v[2];}

int const* data() const {return v;}
int* data() {return v;}

private:
int v[3];
};

Au niveau performances, il ne devrait y avoir aucune pénalité
car les functions sont inline. Par contre le prix à payer est
de devoir écrire "p.x()" au lieu de simplement "p.x".

--
Sylvain Togni

1 2