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 :

Différence entre détruire un objet et désallouer un espace ?


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Ingénieur à ses heures perdues
    Inscrit en
    Août 2011
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur à ses heures perdues

    Informations forums :
    Inscription : Août 2011
    Messages : 36
    Par défaut Différence entre détruire un objet et désallouer un espace ?
    Bonjour à tous,

    En plein apprentissage du C++ j'en arrive au chapitre sur la gestion de la mémoire où l'on a introduit la classe allocator incluse dasn <memory>. On donne quelques fonctions de cette classe et j'ai du mal à comprendre la différence entre deux de ces fonctions.

    voici à quoi ressemble une version simplifiée de cette classe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template<class T> class allocator {
    public:
        // ...
        T* allocate(int n);            // allocate space for n objects of type T
        void deallocate(T* p, int n);  // deallocate n objects of type T starting at p
     
        void construct(T* p, const T& v); // construct a T with the value v in p
        void destroy(T* p);            // destroy the T in p
    };
    Quel est la différence entre deallocate et destroy au niveau de la mémoire ? D'après ce que je semble avoir compris, deallocate libère la mémoire pointé par p = et destroy libère les emplacements mémoire aux adresse où se trouve les pointeurs c'est à dire &p[i]. C'est bien ça ?

    Merci d'avance

  2. #2
    Membre éclairé
    Avatar de Captain'Flam
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2011
    Messages
    273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Février 2011
    Messages : 273
    Billets dans le blog
    1
    Par défaut
    Difficile de répondre sans le code de la classe allocator, mais en tout cas :

    allouer = réserver de la place sur le tas (heap) comme on peut le faire avec un vulgaire malloc (en C) => le système prend note que cette zone de mémoire t'appartient et n'y touchera pas tant que tu ne l'auras pas désallouée.

    désallouer = rendre la place que l'on avait réservée => le système peut maintenant en faire ce qu'il veut (par exemple l'allouer à quelqu'un d'autre).

    construire = appeler la constructeur d'un objet. Ce dernier n'est rien de plus qu'une fonction qui peut aller de ne-rien-faire à faire-des-tas-de-trucs-très-compliqués. Le constructeur ne peut (pratiquement) pas être appeler explicitement. C'est le compilateur qu'il la fait au moment de l'instanciation de ton objet.

    détruire = appeler le destructeur d'un objet. Ce dernier est le pendant du constructeur. Il doit "nettoyer" l'objet avant que ce dernier ne disparaisse. par exemple, si ton objet a alloué de la mémoire, il faut la désallouer à ce moment là.

    Le new est un opérateur C++ qui fait 2 choses : allocation + construction.
    Par exemple : "std::string * s = new std::string ;" va allouer la place nécessaire à un objet de type std::string puis appeler son constructeur. Ce dernier va initialiser toutes les membres de ton s afin qu'il soit prêt à l'emploi.
    "std::string s ;" ne fait pas d'allocation mais appelle seulement le constructeur.

  3. #3
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    La différence est subtile en C++ parce que new (respectivement delete) a le double effet d'allouer l'espace mémoire nécessaire (respectivement de la libérer) pour stocker l'objet et de l'initialiser grâce à appel au constructeur(respectivement grace à un appel au destructeur).

    Si tu ne fais pas appel à new, par exemple avec le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int main()
    {
        MyClass obj(arg1,arg2);
    }
    l'objet est construit (sur ce que l'on appelle la pile) et existera "tant que l'on n'aura pas quitté la portée dans laquelle il est construit", mais tu n'auras pas forcément d'allocation de mémoire (au sens où on l'entend généralement), car la construction de ces membres peut ne pas nécessiter d'allocation de mémoire.

    De même, lorsque tu quitte la portée dans laquelle obj est construit (comprend : lorsque tu arrive à l'accolade fermante correspondant à celle représentant le bloc dans lequel l'objet est construit), l'appel implicite au destructeur ne provoquera pas forcément de libération de mémoire (vu qu'il y a normalement symétrie entre le travail du constructeur et du destructeur).

    Enfin, lorsque l'on parle d'allocation de la mémoire c'est essentiellement pour deux raisons possibles:
    1. Soit, c'est parce que l'on souhaites prendre le contrôle de la durée de vie de l'objet (vu qu'un objet créé par new ne sera détruit (et la mémoire qu'il utilise libérée) que lorsque l'on appellera explicitement delete sur le pointeur "pointant" vers l'objet)
    2. soit, c'est parce que l'on souhaite pouvoir utiliser le polymorphisme et que l'on ne sait pas, à un instant T, quel sera le type exact de l'objet.
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Membre averti
    Homme Profil pro
    Ingénieur à ses heures perdues
    Inscrit en
    Août 2011
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur à ses heures perdues

    Informations forums :
    Inscription : Août 2011
    Messages : 36
    Par défaut
    Citation Envoyé par koala01 Voir le message
    [*]soit, c'est parce que l'on souhaite pouvoir utiliser le polymorphisme et que l'on ne sait pas, à un instant T, quel sera le type exact de l'objet.[/LIST]
    C'est précisément dans ce contexte que j'ai abordé ce problème. Précisément, dans le livre sur lequel j'apprend on essaye de reconstruire le conteneur vector de la STL. Pour cela on définit plusieurs fonctions dont une qui a la charge de réserver de la mémoire lorsqu'on en a besoin. Ma définition de 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
    template<class T, class A = allocator<T> > class vector {
        A alloc;    // use allocate to handle memory for elements
        int sz;     // the size
        T* elem;    // a pointer to the elements
        int space;  // size+free_space
    public:
        vector() : sz(0), elem(0), space(0) { }    
        vector(int s);
        vector(const vector&);            // copy constructor
        vector& operator=(const vector&); // copy assignment
        ~vector() { delete[ ] elem; }     // destructor
     
        void resize(int newsize, T def = T()); // growth
        void push_back(const T& d);
        void reserve(int newalloc);
    };
    Ma fonction reserve :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template<class T, class A> 
    void vector<T,A>::reserve(int newalloc)
    {
        if (newalloc<=space) return;     // never decrease allocation
        T* p = alloc.allocate(newalloc); // allocate new space
        for (int i=0; i<sz; ++i) alloc.construct(&p[i],elem[i]); // copy
        for (int i=0; i<sz; ++i) alloc.destroy(&elem[i]);        // destroy
        alloc.deallocate(elem,space);    // deallocate old space
        elem = p;
        space = newalloc;    
    }
    Et c'est précisément ces 3 lignes là qui me pose problème :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    for (int i=0; i<sz; ++i) alloc.destroy(&elem[i]);        // destroy
    alloc.deallocate(elem,space);    // deallocate old space
    elem = p;
    Après chaque ligne, que se passe-t-il précisément dans la mémoire ? Et comment se fait il que nous puissions encore manipuler elem après l'avoir détruit ?

  5. #5
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Non, le cas présent représente une troisième raison "classique" (que l'on évite au maximum grace, entre autres, aux classes fournies par la STL, pour de simples histoires de sécurité et de facilité) : parce que l'on ne connait pas, au moment où l'on écrit le code, le nombre exact d'objet que l'on devra gérer

    L'idée ici est de se dire que l'on va devoir gérer "un nombre inconnu" d'objets (de type connu, même si c'est un type générique, et donc dont la taille est aussi connue ) et qu'il faut s'assurer de "ne rien perdre" (que ce soit en espace mémoire ou en terme d'éléments stockés dans la classe) lorsque l'on va devoir augmenter la taille du vecteur.

    On commence donc par allouer un espace mémoire suffisant pour pouvoir représenter "newalloc" élément.

    Puis on passe en revue tous les éléments déjà présent dans le vecteur et on les copie à leur nouvelle place (de l'invocation de construct dans la boucle for)
    Pour etre sur que les éléments qui se trouvent dans "l'ancien espace que l'on a utilisé", soient correctement détruit (et que l'espace mémoire nécessaire à leur maintient en mémoire soit correctement libéré), on invoque ensuite destroy sur chacun d'eux (c'est le but de la boucle en question )

    On termine en prenant "newalloc" et "p" comme nouvelles valeur de référence

    Si tu as ne serait-ce qu'un tout petit peu travaillé en C, c'est un fonctionnement dont tu es sans doute coutumier (à coup de malloc et de free + copie de valeurs )
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Membre averti
    Homme Profil pro
    Ingénieur à ses heures perdues
    Inscrit en
    Août 2011
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur à ses heures perdues

    Informations forums :
    Inscription : Août 2011
    Messages : 36
    Par défaut
    Je te remercie. Tout devient clair à présent. Et non je n'ai pas trop travaillé en C. Je connais les bases, mais je n'ai pas beaucoup pratiqué.

    Merci !

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

Discussions similaires

  1. Réponses: 5
    Dernier message: 14/11/2016, 20h35
  2. Différence entre EJB et "objets en session"
    Par zaitsev dans le forum Langage
    Réponses: 4
    Dernier message: 15/02/2012, 13h11
  3. Réponses: 0
    Dernier message: 11/12/2010, 20h36
  4. Différence entre reférence et objet
    Par heeedi dans le forum Débuter avec Java
    Réponses: 4
    Dernier message: 23/05/2009, 14h08
  5. différence entre table et objet
    Par karinal dans le forum UML
    Réponses: 2
    Dernier message: 08/07/2008, 15h39

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