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

sizeof et virtual

20 réponses
Avatar
Aurélien Barbier-Accary
Bonjour,

avant ma question, voici les données :

class cA
{
protected:
double d;
public:
cA(const double& d =0.0) { this->d = d; }
~cA(void) {}
};

class cB
{
protected:
double d;
public:
cB(const double& d =0.0) { this->d = d; }
virtual ~cB(void) {}
};

cout << "sizeof(cA) = " << sizeof(cA) << endl; // => 8
cout << "sizeof(cB) = " << sizeof(cB) << endl; // => 16

est-ce normal ?
peut-on garder une taille de 8 en utilisant des fonctions virtuelles ?

Merci.

Aurélien.

10 réponses

1 2
Avatar
Marc Boyer
Aurélien Barbier-Accary a écrit :
avant ma question, voici les données :

class cA
{
protected:
double d;
public:
cA(const double& d =0.0) { this->d = d; }
~cA(void) {}
};

class cB
{
protected:
double d;
public:
cB(const double& d =0.0) { this->d = d; }
virtual ~cB(void) {}
};

cout << "sizeof(cA) = " << sizeof(cA) << endl; // => 8
cout << "sizeof(cB) = " << sizeof(cB) << endl; // => 16

est-ce normal ?


Oui.

peut-on garder une taille de 8 en utilisant des fonctions virtuelles ?


Ben, ça va être dur. Dans un polymorphisme dynamique,
il faut pouvoir, à l'exécution, savoir retrouver le type
réel de l'objet. Et cela demande un peu plus d'info
que sur un typage statique.

Marc Boyer
--
À vélo, prendre une rue à contre-sens est moins dangeureux
que prendre un boulevard dans le sens légal. À qui la faute ?

Avatar
Stan
"Aurélien Barbier-Accary" a écrit dans le
message de news:434ced6a$0$13516$
| Bonjour,
|
| cout << "sizeof(cA) = " << sizeof(cA) << endl; // => 8
| cout << "sizeof(cB) = " << sizeof(cB) << endl; // => 16
|
| est-ce normal ?
| peut-on garder une taille de 8 en utilisant des fonctions virtuelles ?
|


Dans quel but as-tu besoin d'avoir cette information ?
En fonction du problème à résoudre, il a surement une méthode plus
adaptée à ton cas.

--
-Stan .
Avatar
Jean-Marc Bourguet
Aurélien Barbier-Accary writes:

Bonjour,

avant ma question, voici les données :

class cA
{
protected:
double d;
public:
cA(const double& d =0.0) { this->d = d; }
~cA(void) {}
};

class cB
{
protected:
double d;
public:
cB(const double& d =0.0) { this->d = d; }
virtual ~cB(void) {}
};

cout << "sizeof(cA) = " << sizeof(cA) << endl; // => 8
cout << "sizeof(cB) = " << sizeof(cB) << endl; // => 16

est-ce normal ?


Oui.

peut-on garder une taille de 8 en utilisant des fonctions
virtuelles ?


Ça me semble difficile. S'il y a un membre virtuel, il faut
stocker une information de type. Note qu'il y a des chances
(en particulier si tu ne compiles pas en mode 64 bits)
qu'elle ne prenne pas la taille d'un double, mais que les
contraintes d'alignement fassent que les doubles soient
containts d'avoir une adresse multiple de 8, donc que les
types contenant des doubles aient une taille multiple de 8.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Arnaud Debaene
Aurélien Barbier-Accary wrote:
Bonjour,

avant ma question, voici les données :

class cA
{
protected:
double d;
public:
cA(const double& d =0.0) { this->d = d; }
~cA(void) {}
};

class cB
{
protected:
double d;
public:
cB(const double& d =0.0) { this->d = d; }
virtual ~cB(void) {}
};

cout << "sizeof(cA) = " << sizeof(cA) << endl; // => 8
cout << "sizeof(cB) = " << sizeof(cB) << endl; // => 16

est-ce normal ?
Oui : Sur tous les compilateurs courants, le fait d'avoir une fonction

virtuelle dans une classe signifie que un objet de ce type embarque une
donnée membre cachée "v-ptr" (pour "virtual pointer") qui pointe sur une
description générée par le compilateur du type réel de l'objet (le plus
souvent, cette description est appelée la "v-table" parce qu'elle contient
entre autres choses une table de pointeurs sur les méthodes virtuelles de la
classe). Par contre, ce surcout est fixe et n'augmente pas avec le nombre de
méthodes virtuelles.

peut-on garder une taille de 8 en utilisant des fonctions virtuelles ?
Non. Le plus petit que tu puisse *peut être* obtenir c'est sizeof(double) +

taille d 'un pointeur, soit 12 sur les machines 32 bits courantes, en jouant
sur les options d'alignement et de padding du compilateur (ce qui dégradera
probablement les performances, si c'est seulement possible). C'est si
important que çà?

Arnaud

Avatar
Aurélien Barbier-Accary

est-ce normal ?


Oui.

peut-on garder une taille de 8 en utilisant des fonctions virtuelles ?



Ben, ça va être dur. Dans un polymorphisme dynamique,
il faut pouvoir, à l'exécution, savoir retrouver le type
réel de l'objet. Et cela demande un peu plus d'info
que sur un typage statique.

Marc Boyer


Il me semblait bien mais le rêve reste permis ;-p

En fait ce qui me choque plus c'est que la taille ne soit pas 12, je pensais
qu'un pointeur suffisait pour la table virtuelle.
Et je croyais naîvement aussi que pour la classe mère la table virtuelle était
inutile (j'en reste convaincu mais apparemment l'économie n'est pas faite) et
qu'elle n'était utilisée que pour des instances de classes filles.

Merci pour ta réponse.


Avatar
Aurélien Barbier-Accary
Oui : Sur tous les compilateurs courants, le fait d'avoir une fonction
virtuelle dans une classe signifie que un objet de ce type embarque une
donnée membre cachée "v-ptr" (pour "virtual pointer") qui pointe sur une
description générée par le compilateur du type réel de l'objet (le plus
souvent, cette description est appelée la "v-table" parce qu'elle contient
entre autres choses une table de pointeurs sur les méthodes virtuelles de la
classe). Par contre, ce surcout est fixe et n'augmente pas avec le nombre de
méthodes virtuelles.


Effectivement, après plusieus tests de définitions de classes (virtuelles ou
pas) contenant des objets virtuels ou pas j'ai vu que la taille augmente de 8
pour chaque virtual.

peut-on garder une taille de 8 en utilisant des fonctions virtuelles ?


Non. Le plus petit que tu puisse *peut être* obtenir c'est sizeof(double) +
taille d 'un pointeur, soit 12 sur les machines 32 bits courantes, en jouant
sur les options d'alignement et de padding du compilateur (ce qui dégradera
probablement les performances, si c'est seulement possible).


Comme je l'ai dit dans ma réponse à Marc je m'attendais plus à un surcoût de 4
(un pointeur).
Ca m'étonne un peu que ce ne soit du qu'à un "problème" d'alignement. Ce doit
pourtant être le cas puisque Jean-Marc (merci aussi pour ta réponse) et toi en
avez l'air convaincu.
Saurais-tu où je peux trouver une description complète de la structure d'une
classe virtuelle s'il te plait ?

C'est si important que çà?



Oui, car le phénomène se produit en cascade et devient "visiblement" coûteux
pour les grosses structures.
Pour plus de détails, cf ma réponse à Stan :-)

Merci pour toutes ces infos.

Aurélien.


Avatar
Aurélien Barbier-Accary
Dans quel but as-tu besoin d'avoir cette information ?
En fonction du problème à résoudre, il a surement une méthode plus
adaptée à ton cas.



Bonjour et merci pour ta réponse,

Dans mon appli je travaille avec des BlobTrees qui sont des arbres CSG enrichis,
c'est-à-dire qu'un objet (3D) est défini par des mélanges, unions, intersections
et différences de primitiives géométriques.
Ces primitives sont composés d'un squelette géométrique et d'une peau implicite
(pour les mélanges).
Chaque squelette est composé de points, vecteurs et quelques grandeurs.
Comme les modèles sont animés, en fait il s'agit de trajectoires, vecteurs
dépendants du temps et grandeurs variables.
Et enfin si je me restreint aux trajectoires j'ai besoin que certaines soient
définies relativement à d'autres (gestion et édition simplifiée) donc j'utilise
beaucoup des compositions de trajectoires, vecteurs et gandeurs.
Si on ajoute à ça le fait que ces modèles sont à niveaux de détails, finalement
la structure est assez importante mais surtout elle ne contient que des objets
qui sont des instances de classes virtuelles (de BlobTrees, de primitives, de
squelettes, des trajectoires, ...).
Et comme ce qui m'intéresse vraiment est de gérer plusieurs objets et de faire
des transformations entre eux...

Bref ça coûte finalement assez cher ces 8+8+...+8 octets en plus pour chaque
virtual.
Je n'y avais jamais trop réfléchi avant mais comme je suis en train de tout
recoder pour avoir une architecture ds mes libs plus propre, je voudrais faire
les choses bien.
Je ne vois pas trop si c'est améliorable finalement.

Aurélien.

Avatar
Marc Boyer
Aurélien Barbier-Accary a écrit :
Ben, ça va être dur. Dans un polymorphisme dynamique,
il faut pouvoir, à l'exécution, savoir retrouver le type
réel de l'objet. Et cela demande un peu plus d'info
que sur un typage statique.



Il me semblait bien mais le rêve reste permis ;-p


Oui, une machine où on stockerait plus d'une information
par bit ;-)

En fait ce qui me choque plus c'est que la taille ne soit pas 12, je pensais
qu'un pointeur suffisait pour la table virtuelle.


Il suffit.
Mais ce sont les "contraintes d'alignements". A priori, tu peux faire
un tableau de ton type, et le compilateur veut que chaque instance
commence à une adresse multiple de 8. Donc, il a besoin que la taille
totale de l'objet soit un multiple de 8.

Et je croyais naîvement aussi que pour la classe mère la table virtuelle était
inutile (j'en reste convaincu mais apparemment l'économie n'est pas faite) et
qu'elle n'était utilisée que pour des instances de classes filles.


Oui, mais quand il tombe sur un pointeur A* p, il va devoir lire
*p pour savoir dynamiquement si c'est la mère ou la fille. Donc,
il faut que même dans le cas de la mère, il existe une info qui
dise "je suis la mère".

Marc Boyer
--
À vélo, prendre une rue à contre-sens est moins dangeureux
que prendre un boulevard dans le sens légal. À qui la faute ?


Avatar
Marc Boyer
Aurélien Barbier-Accary a écrit :
Dans quel but as-tu besoin d'avoir cette information ?
En fonction du problème à résoudre, il a surement une méthode plus
adaptée à ton cas.


Dans mon appli je travaille avec des BlobTrees qui sont des arbres CSG enrichis,
c'est-à-dire qu'un objet (3D) est défini par des mélanges, unions, intersections
et différences de primitiives géométriques.
Ces primitives sont composés d'un squelette géométrique et d'une peau implicite
(pour les mélanges).
Chaque squelette est composé de points, vecteurs et quelques grandeurs.
Comme les modèles sont animés, en fait il s'agit de trajectoires, vecteurs
dépendants du temps et grandeurs variables.
Et enfin si je me restreint aux trajectoires j'ai besoin que certaines soient
définies relativement à d'autres (gestion et édition simplifiée) donc j'utilise
beaucoup des compositions de trajectoires, vecteurs et gandeurs.
Si on ajoute à ça le fait que ces modèles sont à niveaux de détails, finalement
la structure est assez importante mais surtout elle ne contient que des objets
qui sont des instances de classes virtuelles (de BlobTrees, de primitives, de
squelettes, des trajectoires, ...).
Et comme ce qui m'intéresse vraiment est de gérer plusieurs objets et de faire
des transformations entre eux...

Bref ça coûte finalement assez cher ces 8+8+...+8 octets en plus pour chaque
virtual.


+8 pour chaque virtual ? Normalement, on ne paye ce +8 qu'une fois
il me semble.

Je n'y avais jamais trop réfléchi avant mais comme je suis en train de tout
recoder pour avoir une architecture ds mes libs plus propre, je voudrais faire
les choses bien.
Je ne vois pas trop si c'est améliorable finalement.


Ben, les contraintes d'alignement, ça va être difficile de passer
outre. La première chose, c'est de voir si le compilateur propose
plusieurs options pour les structures. Je sais que les x86 accèptent
les accès non alignés (avec perte de perfs), donc peut etre que
ton compilateur sait en tirer partie.

Eventuellement, tu peux non pas stoquer un double mais un
unsigned char t[sizeof double], et ne pas accéder à ta variable,
mais passer par une fonction qui va la recalculer systématiquement.

double getValue(){
double res;
memcpy(&res, t, sizeof(res) );
return res;
}

void setValue(double d){
memcpy(t, &d);
}

Marc Boyer
--
À vélo, prendre une rue à contre-sens est moins dangeureux
que prendre un boulevard dans le sens légal. À qui la faute ?


Avatar
Aurélien Barbier-Accary
Et je croyais naîvement aussi que pour la classe mère la table virtuelle était
inutile (j'en reste convaincu mais apparemment l'économie n'est pas faite) et
qu'elle n'était utilisée que pour des instances de classes filles.



Oui, mais quand il tombe sur un pointeur A* p, il va devoir lire
*p pour savoir dynamiquement si c'est la mère ou la fille. Donc,
il faut que même dans le cas de la mère, il existe une info qui
dise "je suis la mère".

Marc Boyer


oups :-O
exact.


1 2