IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Petite question de memoire


Sujet :

C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Février 2005
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 17
    Par défaut Petite question de memoire
    Salut,

    Par simple curiosite, je me demandais comment le compilateur defini l'espace memoire necessaire a un objet.

    Par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class Vecteur  
    {
    private:
    	double	m_x;
    	double	m_y;
    	double	m_z;
    	...
    }
    Puisqu'un double prend 8 bytes et que j'en ai 3, je pensais que la taile d'un objet Vecteur serait de 24 bytes.

    En faisant:
    J'obtiens 32!!! D'ou provient le 8 bytes de plus? Il sert a quoi?

    CaptnB

  2. #2
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 29
    Par défaut
    attention : 1 byte = 1 octet = 8 bits

    Moi ça fait bien 24 avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class test
    {
    private:
    double d1;
    double d2;
    double d3;
    };
    PS : gcc 3.3.6

  3. #3
    Membre émérite Avatar de Caine
    Inscrit en
    Mai 2004
    Messages
    1 028
    Détails du profil
    Informations personnelles :
    Âge : 53

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 028
    Par défaut
    Ceci provient du pointeur this de la classe.

    Une classe vide fait 4 octets.

  4. #4
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class Vecteur  
    { 
    private: 
       double   m_x; 
       double   m_y; 
       double   m_z; 
       ... 
    }
    Et qu'est ce qui se cache derrière les ... ?

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Février 2005
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 17
    Par défaut
    Bon... mon exemple devait pas etre bon

    La classe pour laquelle j'ai teste a bel et bien trois membres de type double mais elle a aussi quelques methodes dont j'ai pas ecrit les details (des surcharges d'operateurs pour la plupart, question de simplifier les calculs vectoriels). Dans tout les cas, mes instances font 32 octets et pas 24...

    Voici la classe:
    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    class CVector : public CObject  
    {
    	// Friend functions
    	friend CVector operator*(double mult, CVector vec);		// Multiply scalar by a vector
     
    private:
    	//  Member variables
    	double	m_sta;		// Staion (x coordinate)
    	double	m_bl;		// Butt line (y coordinate)
    	double	m_wl;		// Water line (z coordinate)
     
    public:
    	// Default constructor / destructor
    	CVector();
    	virtual ~CVector();
     
    	//  Overloaded operators and copy construtor
    	CVector(const CVector& copy);
    	CVector operator=(const CVector& aff);
    	CVector operator-();					// Invert vector
    	CVector operator/(const double div);	// Divide vector by a scalar
    	CVector operator*(const double mult);	// Multiply vector by a scalar
    	CVector operator*(const CVector vec);	// Cross product
    	CVector operator+(const CVector vec);	// Sum
    	CVector operator-(const CVector vec);	// Difference
    	double operator%(const CVector vec);	// Dot product (% has same precedence than * and /, don't confuse with modulo)
    	double operator^(const CVector vec);	// Angle between the vectors
     
    	//  Get / Set functions
    	double GetBl() const;
    	double GetSta() const;
    	double GetWl() const;
     
    	double GetNorm() const;
     
    	void SetBl(const double bl);
    	void SetSta(const double sta);
    	void SetWl(const double wl);
     
    	void Set(const double sta, const double bl, const double wl);
    	void Set(const CPt* pt1, const CPt* pt2);		// CVector from pt1 to pt2
     
    	// Other
    	void Unit();		// Transform the vector into a unit vector
     
    	CString WriteVector();
    };

    CaptnB

  6. #6
    Modérateur
    Avatar de bruno_pages
    Homme Profil pro
    ingénieur informaticien à la retraite
    Inscrit en
    Juin 2005
    Messages
    3 545
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 65
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : ingénieur informaticien à la retraite
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2005
    Messages : 3 545
    Par défaut
    Citation Envoyé par Caine
    Ceci provient du pointeur this de la classe.

    Une classe vide fait 4 octets.
    houla houla, this n'est pas mémorisé dans une instance de classe, this contient l'adresse de l'instance courante.

    S'il arrive qu'il y ai 4 octets supplémentaires utilisés par instance c'est pour mémoriser l'adresse du vecteur de opérations virtuelles qui est partagé par toutes les instances d'une meme classe. Une classe sans opération virtuelle (hérité ou non) n'a pas besoin de ce vecteur ... ni de mémoriser son adresse.
    Bruno Pagès, auteur de Bouml (freeware), mes tutoriels sur DVP (vieux, non à jour )

    N'oubliez pas de consulter les FAQ UML et les cours et tutoriels UML

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Février 2005
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 17
    Par défaut
    Humm.....

    4 octets pour le pointeur this...

    Donc je presume que si ma classe a 8 octets de trop, il y en a 4 pour le pointeur sur le CVector et 4 pour le pointeur sur le CObject (classe de base).

    C'est ca???


    CaptnB

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2005
    Messages : 45
    Par défaut
    Je dit peut être une idiotie, mais le pointeur this ne permet pas d' acceder à une classe mére...

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Février 2005
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 17
    Par défaut
    A la lumiere de vos explications, j'ai fait d'autres tests. J'ai une classe virtuelle pure qui n'a qu'un int et un CString comme membre. Donc, je devrais avoir 8 octets pour les donnees. En incluant le destructeur, j'ai 10 fonctions membres qui sont virtuelles, donc 40 octets. Je serais suppose obtenir 40 + 8 mais la, j'obtiens juste 12....le mystere persiste!

    CaptnB

    P.S. Ca m'empeche pas de fonctionner mais, comme je l'ai dit dans mon premier post, j'suis assez curieux de savoir

  10. #10
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    La taille d'une classe dépend de beaucoup de choses.

    - La taille des données membres bien sûr.
    - L'alignement mémoire (par défaut l'alignement est généralement à 4 octets).
    - La v-table pour les classes comportant des fonctions virtuelles (un seul pointeur -- vers la v-table (puisqu'elle est commune à toutes les instances de la classe)).

    D'autant plus qu'il me semble que la norme n'impose rien là-dessus, ça peut varier selon les compilos (à vérifier).

  11. #11
    Modérateur
    Avatar de bruno_pages
    Homme Profil pro
    ingénieur informaticien à la retraite
    Inscrit en
    Juin 2005
    Messages
    3 545
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 65
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : ingénieur informaticien à la retraite
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2005
    Messages : 3 545
    Par défaut
    Sur une machine 32 bits l'alignement est de 4 octets meme pour des doubles qui sont mémorisés sur 8 octets.

    Les compilateurs cherchent à minimiser la taille des données, y compris en gérant les coupures liées aux héritages :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    class C1 {
       public: // pas important ici
           char c1;
    };
     
    class C2 : public C1 {
       public: // pas important ici
           char c2;
    };
    sizeof(C1) == 1 et sizeof(C2) == 2, c.a.d. le début de C2 n'est pas aligné sur 4 octets, mais lors des allocations le début de C1 le sera

    Comme je l'ai dis ainsi que loulou24, le vecteur des virtual est une donnée globale partagée dont seule l'adresse est mémorisée dans les instances, bref le nombre d'opérations virtuelles change la taille du vecteur, pas la taille des instances (ouf !). Le but de ce vecteur est de permettre l'appel rapide en temps constant d'une opération virtuelle.

    Supposons les defs C++ suivantes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    class C1 {
      public: // pas important
        virtual void a();
        virtual void b();
    };
     
    class C2 : public C1 {
      public: // pas important
        virtual void a();
        virtual void c();
    };
    le compilo génère quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    void * vt_C1[] = {
      (void *) &C1::a,
      (void *) &C1::b
    };
     
    void * vt_C2[] = {
      (void *) &C2::a,
      (void *) &C1::b,   // non redéfini dans C2
      (void *) &C2::c
    };
    Dans chaque instance reelle de C1 (ie par un C2 ou autre sous classe) les 4 premiers octets contiennent l'adresse de vt_C1
    Dans chaque instance reelle de C2 (ie pas une sous classe) les 4 premiers octets contiennent l'adresse de vt_C2

    Soit x est une instance de C1 ou C2 ou autre classe qui hérite de C1.
    Le code genere pour x->a() est alors simplement quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ((void(*)()) (*((void ***) x))[0])();
    Le code genere pour x->b() est alors simplement quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ((void(*)()) (*((void ***) x))[1])();
    etc ... meme si 1000 classes héritent de C1

    Les code si dessus sont donnés comme exemple, je ne dis pas que c'est exactement ce que font les compilateurs. De meme lorsque de dis que les 4 premiers octets d'une instance contiennent l'adresse du vecteur des virtuels cela peut etre les 4 octets qui précèdent l'adresse au sens this etc ...
    Bruno Pagès, auteur de Bouml (freeware), mes tutoriels sur DVP (vieux, non à jour )

    N'oubliez pas de consulter les FAQ UML et les cours et tutoriels UML

  12. #12
    Membre chevronné
    Avatar de matazz
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    471
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 471
    Par défaut
    tu peut soit parametrer ton environnement par exemple sous Visual C++ tu peut régler l'alignement mémoire à un 1 Byte, mais tu peut aussi utiliser les bitfields du C : (je crois pas que ça fonctionne sur les classes, que sur les struct à confirmer)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    struct Bitfield
         {
         unsigned int BoolSur1Bit :1; 
         int EntierSur7Bit :7;  
         float FlottantSur8Bits :8;
         }
    si tu fias un sizeof() tu auras 2

  13. #13
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Par défaut
    Citation Envoyé par CaptnB
    Je serais suppose obtenir 40 + 8 mais la, j'obtiens juste 12....le mystere persiste!
    Non : la VMT est référencée par un UNIQUE pointeur, qui pointe donc sur une table construite soit à la compilation, soit à l'initialisation du programme (dans le segment de démarrage du programme, je ne sais plus s'il porte un nom particulier en C++). En effet, toutes les instances d'une même classe possèdent la même VMT !!

    En gros, si tous tes attributs sont statiques, tu n'as pas d'attributs "réels", et la taille de ta classe est "nulle" (souvent, un octet quand même pour éviter les effets de bord).
    Si toutes tes méthodes sont non-virtuelles, pas de pointeur de VMT.

    En fonction de ta classe, tu vas donc avoir 0 ou 4 octets en plus suivant la présence de la VMT, et en fonction de l'alignement, tu peux avoir entre zéro et (Na-1) octets par attribut de "perte" (alignement Na à 1, 2, 4, 8 et même 16 octets sur les machines modernes).

    Calcule les tailles de ces classes, par exemple :
    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
    27
    28
    class StaticNoVMT {
    	static char Field1 ;
    	static int Field2 ;
    	void Method ( int Param1 ) ;
    } ;
     
    class StaticWithVMT {
    	static char Field1 ;
    	static int Field2 ;
    	virtual void Method ( int Param1 ) ;
    } ;
     
    class ThisNoVMT {
    	char Field1 ;
    	int Field2 ;
    	void Method ( int Param1 ) ;
    } ;
     
    class ThisWithVMT {
    	char Field1 ;
    	int Field2 ;
    	virtual void Method ( int Param1 ) ;
    } ;
     
    void StaticNoVMT::Method ( int Param1 ) { Param1++; }
    void StaticWithVMT::Method ( int Param1 ) { Param1++; }
    void ThisNoVMT::Method ( int Param1 ) { Param1++; }
    void ThisWithVMT::Method ( int Param1 ) { Param1++; }
    (Je sais, c'est crade de déclarer comme ça, c'est juste pour l'exemple !!!).

    J'obtiens comme résultats :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Alignement 1 octet :
    Sizeof(char)= 1 bytes
    Sizeof(int)= 4 bytes
    Sizeof(void*)= 4 bytes
    ----------------
    Sizeof(StaticNoVMT)= 1 bytes
    Sizeof(StaticWithVMT)= 4 bytes
    Sizeof(ThisNoVMT)= 5 bytes
    Sizeof(ThisWithVMT)= 9 bytes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Alignement 4 octets :
    Sizeof(char)= 1 bytes
    Sizeof(int)= 4 bytes
    Sizeof(void*)= 4 bytes
    ----------------
    Sizeof(StaticNoVMT)= 1 bytes
    Sizeof(StaticWithVMT)= 4 bytes
    Sizeof(ThisNoVMT)= 8 bytes
    Sizeof(ThisWithVMT)= 12 bytes
    Taille théorique de la classe : 5 octets. Tu remarqueras qu'il n'y a qu'un seul résultat "sizeof" de 5 octets, sur 8 calculs effectués...
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. petite question memoire (en SDL)
    Par fred_sell dans le forum C++
    Réponses: 6
    Dernier message: 29/07/2009, 13h49
  2. [Visuel XP] Petite question sur le theme XP...
    Par ZoumZoumMan dans le forum C++Builder
    Réponses: 12
    Dernier message: 20/01/2005, 14h41
  3. Une petite question
    Par Etienne1 dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 10/08/2004, 16h19
  4. [FOREIGN KEY] petite question bete ...
    Par dzincou dans le forum PostgreSQL
    Réponses: 5
    Dernier message: 13/01/2004, 16h35
  5. Petite question sur les performances de Postgres ...
    Par cb44 dans le forum PostgreSQL
    Réponses: 5
    Dernier message: 13/01/2004, 13h49

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo