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 :

Dans le tas ou dans la pile ?


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juin 2007
    Messages : 3
    Par défaut Dans le tas ou dans la pile ?
    Hello

    J'étudie le C++ depuis quelques temps et je dois avouer que je suis déjà accro :p

    Je connais déjà bien les notions liées à la mémoire, mais en codant un petit programme je me suis posé la question suivante.

    Si je crée un objet dans le tas sans créer explicitement ses propres membres dans le tas, sont-t-il eux aussi crée dans le tas ?

    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
     
    class Objet
    {
    public:
        Objet();
        ~Objet();
     
    // Membres
     
    int premier;
    AutreObjet deuxieme;
    };
     
    int main()
    {
       Objet MonObjet = new Objet();
     
       MonObjet->deuxieme; // cet objet membre est-t-il dans le tas ou dans la pile ?
    }
    A ce que je comprends du système de la pile, logiquement après chaque fin de fonction elle est vidée, donc les membres de mon Objet sont eux aussi dans le tas. Mais comme le corp du programme (main) est aussi une fonction, celà voudrait dire que mes membres sont dans la pile ?

    J'ai un doute qui m' habite même la nuit lol

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 299
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 299
    Par défaut
    Salut, si tu fais un new, ta variable sera dans le tas, sinon elle sera dans la pile. une variable dans la pile est immédiatement détruite à la fin du bloc. En revanche, une variable dans le tas ne sera détruite que si tu fais un delete.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    int main()
    {
       Objet MonObjet = new Objet();
     
       MonObjet->deuxieme; // cet objet membre est-t-il dans le tas ou dans la pile ?
    }
    ne serait-ce pas plutôt

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    int main()
    {
       Objet * MonObjet = new Objet();
     
       MonObjet->deuxieme; // cet objet membre est-t-il dans le tas ou dans la pile ?
    }
    en faisant new Objet() tu as réservé suffisament de place dans la pile pour créer ton objet Objet. Pour moi, MonObjet-> deuxieme est dans le tas

  3. #3
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Objet MonObjet = new Objet();
    Ce code n'est pas du C++. Je suppose que tu voulais dire "Objet* MonObjet = new Objet();", car le new n'a pas de sens en C++ pour un objet sur la pile.

    Les données membres d'un objet sont toujours dans le "corps" de l'objet (bien sûr, pour un pointeur, c'est le pointeur qui est dans l'objet, pas les données pointées).
    Ainsi, si tu alloues Objet sur le tas, ses deux variables premier et deuxieme seront à la suite sur le tas, à l'endroit pointé par MonObjet.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  4. #4
    Membre chevronné
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    366
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 366
    Par défaut
    En fait, des que tu fait new , tu es dans le tas. Par exemple,

    class A {

    public:

    A(){

    p = new int;
    }

    int * p;
    };

    int f(){

    A a;

    }
    L instance "a" de A est bien sur la pile. En revanche si le membre p, en tant pointeur est lui aussi sur la pile, la zone memoire pointee par p (le int) est sur le tas. A la sortie de f, "a" qui est sur la pile est detruit , ainsi que tout ces membres : la zone mmeoire sur l entier n etant pas un membre , elle n est pas liberee -> memorie leak

  5. #5
    Candidat au Club
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juin 2007
    Messages : 3
    Par défaut
    J'ai oublié l'astérisque dans l'exemple (bonk me), mais j'en pensais pas moins. Merci beaucoup pour vos réponses, ce doute venait du faite qu'on utilise le point (.) pour accèder à un membre d'un objet dans la pile, j'ai associé cette syntaxe d'accès comme étant exclusivement pour la pile.

    Voilà pourquoi j'ai eu ce doute:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    Objet * pMonObjet = new Objet();
     
    pMonObjet->deuxieme; // Dans le tas
     
    Objet MonDeuxiemeObjet();
    MonDeuxiemeObjet.deuxieme; // Dans la pile
     
    pMonObjet->deuxieme.m_Membre; // Le membre de deuxieme est dans le tas.
    Voilà ce que je comprends maintenant:

    "->" n'est pas exclusivement un operateur d'accès membre dans le tas, mais une simplification de syntaxe évitant ainsi de devoir déréférencer le pointeur avant de pouvoir accéder au membres:
    L'operateur point (.) n'est donc pas exclusivement utilisé pour l'accès membre dans la pile mais d'une façon générale sur un objet (ou un objet pointé) qui n'est pas un pointeur. D'où le nom de cette opérateur syntaxique "->" anglais "Pointer".

    Merci encore

  6. #6
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Attention, ceci ne crée pas l'objet, mais déclare une fonction:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Objet MonDeuxiemeObjet();
    Quand on instancie un objet sur la pile avec le constructeur par défaut, il ne faut pas mettre les parenthèses.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Il semblerait que tu n'aies pas compris le modèle de données de C++.

    Faisons tout d'abord abstraction des contraintes d'alignement avec ces exemples.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct Objet
    {
        int a;
        int b;
    };
    Disons qu'un int fait 4 octets.
    Par conséquent, Objet est un type qui fait 8 octets, et dont les 4 premiers octets sont l'entier qui correspond à a, et les 4 suivants correspondent à b.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct Objet2
    {
        Objet a;
        int b;
    };
    Ici, Objet2 est un type de taille 12, dont les 8 premiers octets correspondent à un Objet a (soit 4 octets pour un entier puis 4 octets pour un autre) et les 4 suivants correspondent à un entier b.

    Cela est néanmoins un peu plus compliqué à cause de l'alignement. Chaque type primitif dispose de ses contraintes d'alignement. C'est-à-dire que, chaque objet ayant une adresse, l'objet doit avoir une adresse multiple de tel nombre en fonction de son type. Par exemple, sur du x86, un char peut être à n'importe quelle adresse, donc un alignement de 1, un short a un alignement de 2, un int un alignement de 4, un float un alignement de 4 et un double un alignement de 8.
    La taille d'un type doit obligatoirement être un multiple de son alignement, afin de pouvoir en mettre plusieurs directement à la suite. (il serait probablement intéressant de créer un langage sans cette restriction)

    Les types précédents Objet et Objet2 ont donc un alignement de 4.

    Prenons le type suivant.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct Foo
    {
        char a;
        int b;
    };
    b doit nécessairement se trouver à un emplacement mémoire divisible par 4.
    Il n'y a qu'une solution pour garantir cela :
    - donner une contrainte d'alignement de 4 à Foo
    - gaspiller trois octets entre a et b

    Foo fait donc une taille de 8.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct Foo2
    {
        int a;
        char b;
    }
    Il suffit de donner un alignement de 4 à Foo2 pour satisfaire les contraintes d'alignement.
    Néanmoins, la taille de l'objet devant être un multiple de son alignement, il faut encore gaspiller trois octets après b, ce qui donne encore une taille de 8, alors qu'on n'a réellement besoin que de 5 octets.

  8. #8
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Merci pour l'explication Loufoque! J'étais ignorant là dessus!

    Quand tu dis un alignement de 4 pour un int, ça veut dire qu'il fait 4 octets?

Discussions similaires

  1. je veux faire un tri par tas afficher dans une arbre
    Par amam22 dans le forum Débuter
    Réponses: 5
    Dernier message: 26/02/2013, 23h33
  2. Réponses: 11
    Dernier message: 04/01/2010, 17h08
  3. Réponses: 2
    Dernier message: 08/04/2004, 11h11
  4. Réponses: 2
    Dernier message: 19/01/2004, 12h19
  5. Réponses: 6
    Dernier message: 26/01/2003, 13h45

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