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 :

Question existentielle sur allocation de mémoire


Sujet :

C++

  1. #1
    Futur Membre du Club
    Inscrit en
    Mai 2007
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 5
    Points : 5
    Points
    5
    Par défaut Question existentielle sur allocation de mémoire
    Bonjour à tous les développeurs, j'ai une grande question existentielle à vous poser, merci de me dire ce que vous en pensez :

    Pourquoi est il essentiel qu'une classe qui alloue dynamiquement de la mémoire dans le constructeur ait besoin d'une copie de constructeur avec un opérateur d'assignation ?

    Merci mille fois de me donner la philosophie de cette question qui me taraude ...

  2. #2
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Une classe responsable d'une ressource, brute en particulier (de la mémoire allouée à la mano encore plus précisément p.ex), doit expliciter les deux opérations liées à la copie (constructeur de copie et opérateur d'affectation).

    Très rapidement, plusieurs choix possibles :
    - sémantique de copie => définir les deux sous peine de dangling pointeur (wikipédia, FAQ !)
    - interdiction => pour quand on veut pas copiable, comme c'est entre autres le cas pour les données à sémantique de référence
    - possibilité de clonage pour les données à sémantique de référence provenant de hiérarchies polymorphes
    - diverses feintes (idiome enveloppe-lettre, regular objects) pour tout de même avoir une sémantique de copie sur des objets provenant de hiérarchies polymorphes.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  3. #3
    Futur Membre du Club
    Inscrit en
    Mai 2007
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 5
    Points : 5
    Points
    5
    Par défaut Merci bien
    Bonjour,

    Tout d'abord merci pour ces renseignements. Mais comme je suis un peu idiot et de surcroit idiot, je ne comprends toujours pas pourquoi il est essentiel d'avoir une copie de constructeur avec un opérateur d'assignation lorsque le constructeur d'origine alloue DYNAMIQUEMENT de la mémoire ? En gros, je me demande bien pourquoi il faut absolument une copie de contructeur et surtout à quoi ça sert ?

    Ici, vous m'expliquez, avec clarté d'ailleurs, les raisons mais je n'ai malheureusement pas assez de connaissances techniques pour les comprendre totalement...

    Si vous pouviez me dire plus simplement, ce serait ultra sympa de votre part.
    Je sais pas, par exemple que c'est essentiel d'avoir la copie de constructeur pour éviter que l'on puisse faire une copie de la classe ... en d'autres termes, quelquechose que mon cerveau basique puisse comprendre héhé

    Mille Mercis à vous Mr Hermitte et autres Experts !!

  4. #4
    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
    Points : 4 625
    Points
    4 625
    Par défaut
    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
    struct Foo
    {
        int* p;
     
        Foo()
        {
            p = new int(42);
        }
     
        ~Foo()
        {
            delete p;
        }
    };
     
    int main()
    {
        Foo a;
        Foo b = a;
    }
    BIIIIM
    Compris ?
    Boost ftw

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 625
    Points : 30 671
    Points
    30 671
    Par défaut
    Salut,

    Typiquement, si tu utilise un membre alloué dynamiquement, tu vas utiliser une pointeur pour ce membre...

    Le problème, c'est qu'un pointeur n'est jamais que "l'adresse mémoire à laquelle se trouve" la variable réelle... et que, si tu ne définis pas tes propres constructeurs par copie et autres opérateurs d'affectation, le compilateur les ajoutera automatiquement sous une forme de "copie bit à bit" des différents membres...

    Du coup, lorsqu'une copie est effectuée, l'adresse à laquelle se trouve le membre alloué dynamiquement est la meme pour l'objet "source" et pour l'objet "copie"

    Le résultat est moche: lors de la desctruction d'un des deux objets, que ce soit l'objet "source" ou l'objet "copie", le destructeur de l'objet est, fatalement, appelé... et que va-t-on trouver dans le destructeur

    Plus que vraissemblablement un delete du membre alloué dynamiquement

    Pour le premier appel du destructeur, cela se passera sans aucun problème... mais... il y aura toujours un (ou peut etre meme plusieurs) objet(s) dont le membre pointe vers l'adresse mémoire qui était celle à laquelle se trouvait le membre , adressse mémoire qui, par la force des choses, est devenue invalide, et peut tres bien etre allouée à une autre variable

    Du coup, la prochaine tentative d'acces - quelle quelle soit (de l'acces en lecture ou en écriture à une nouvelle tentative de libération du fait du passage dans le destructeur) - à ce membre provoquera une catastrophe, se traduisant le plus souvent par une segmentation vault...

    C'est la raison pour laquelle, si tu utilises un pointeur d'un type donné pour un membre, et que la gestion de la mémoire allouée à ce membre est dévolue à ta classe (allocation ou libération dynamique de la mémoire), il faut que tu fournisse les instructions permettant de garder la cohérence des données lors de la copie

    Entendons nous bien sur le fait que ce n'est pas *uniquement* quand l'allocation dynamique de la mémoire se fait dans le constructeur...

    Une classe formée sur le principe de:
    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
     
    class maclass
    {
        public:
            maclass();
            ~maclass();
            bool MemberIsSet() const;
            void SetMember();
            void UnSetMember();
            Type* GetMember();
        private:
            Type* member;
    };
     
    maclass::maclass():member(NULL)
    {
     
    }
     
    maclass::~maclass()
    {
        delete member;
        member=NULL;
    }
     
    bool malcass::MemberIsSet() const
    {
        return member!=NULL;
    }
     
    void maclass::SetMember()
    { 
        member= new Type;
    }
     
    void maclass::UnsetMember()
    { 
        delete member;
        member=NULL;
    }
     
    Type* maclass::GetMember()
    {
        return member;
    }
    posera tout autant de problème lors de la copie (et surtout lors de la destructions de l'original/de la (des) copie(s) )

    [EDIT] Avec cette classe, tu pourrais prévoir un truc du genre de
    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
     
    int main
    {
        maclass monobjet;
        monobjet.SetMember() //monobjet->member obtient une adresse valide
        foo(monobjet);
        //...
        return 1;
    }
     
    void foo(malcass& copie)
    {
        /* lors de l'appel de foo, le constructeur par copie fournit par le
         * compilateur est appelé... copie->member et monobjet->member
         * de la fonction main pointent tous les deux vers la meme adresse 
         * mémoire
         */
     
    //tout ce qu'il faut faire dans foo
     
         /* lors de la sortie de foo, le destructeur est automatiquement
         * appelé pour copie car la variable sort de sa portée...
         * cela signifie que la mémoire allouée à copie->member est libérée... et,
         * incidemment, celle allouée à monobojet->member de la fonction main
         * (vu que c'est la meme adresse)
         * le fait est que la valeur de monobjet->member n'est pas modifiée pour
         * indiquer qu'il est devenu invalide
         */
    }
    et qui posera problème
    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
    Futur Membre du Club
    Inscrit en
    Mai 2007
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 5
    Points : 5
    Points
    5
    Par défaut Merci pour la clarté !!
    Merci à tous !!

    J'essaierai d'aider les autres aussi bien que vous l'avez fait à mon égard !!

    Bonne nuit

  7. #7
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par koala01
    si tu ne définis pas tes propres constructeurs par copie et autres opérateurs d'affectation, le compilateur les ajoutera automatiquement sous une forme de "copie bit à bit" des différents membres...
    Non, la copie en question n'est pas bit à bit, elle est membre à membre, en utilisant les constructeurs de copies éventuels des différents membres.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

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

Discussions similaires

  1. Réponses: 6
    Dernier message: 16/06/2015, 22h30
  2. question existentielle sur la POO de Fortran
    Par rAyyy dans le forum Fortran
    Réponses: 0
    Dernier message: 07/11/2012, 11h06
  3. Réponses: 4
    Dernier message: 28/10/2010, 10h21
  4. Question débutant sur allocation
    Par LEK dans le forum C
    Réponses: 4
    Dernier message: 29/12/2009, 12h29
  5. Petite question rapide sur allocation mémoire
    Par adn013 dans le forum Langage
    Réponses: 5
    Dernier message: 11/06/2007, 16h10

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