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

Langage C++ Discussion :

new et exception constructeur : que dit la norme pour la désallocation ?


Sujet :

Langage C++

  1. #1
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut new et exception constructeur : que dit la norme pour la désallocation ?
    Bonjour,

    Imaginons que je possède le code suivant :
    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
    #include <iostream>
     
    class Foo{
         public : 
              Foo(void){ throw int(0); }
     
    }
     
    int main(void)
    {
          Foo * ptr = nullptr;
          try {
                ptr = new Foo;
         } catch (int)
         {
                std::cout << ptr << std::endl;
         }
    }
    new va allouer l'espace mémoire puis il va l'initialisé en appelant le constructeur de Foo.
    Mais ce dernier va lancer une exception, je vais donc entrer dans le catch, ptr valant toujours nullptr.

    Il me semblerait logique que new ai lui-même désalloué l'espace qu'il a alloué sinon on risquerait d'avoir des fuites de mémoires.
    Mais que dit exactement la norme à ce sujet ?

    Si j'utilise ensuite un new [], et qu'un seul des constructeur échoue, ce serait dommage qu'il désalloue tout l'espace mémoire et qu'il détruise les objets déjà construits.
    Mais d'un autre côté, comme on a une exception, on ne peux pas récupérer de pointeurs et on se retrouverait dans le cas précédant avec une fuite mémoire.

    Je vois ce que le compilateur doit faire, mais j'aimerais savoir ce qu'en pense la norme.

  2. #2
    Invité
    Invité(e)
    Par défaut
    Si une exception est lancée, ton programme s'arrête (enfin moi s'est le cas) donc obligation de libérer toute la mémoire, sinon, tu auras des fuites de mémoire.

    new [] instancie juste un tableau, mais en aucun cas les éléments de ton tableau, si tu veux tester si un élément de ton tableau à bien été alloué, tu dois faire le test un par un pour chaque élément de ton tableau.

    Tu peux toujours, si tu souhaite que le tableau soit libéré dans n'importe quel cas, utiliser quelque chose comme ceci :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    int main(void)
    {
          std::unique_ptr<Foo[taille]> ptr;
         try {
               ptr = std::make_unique<Foo[taille]>();
         } catch (int)
         {
                std::cout << ptr << std::endl;
         }
    }

    Si j'ai bien compris la norme.

  3. #3
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Citation Envoyé par Lolilolight Voir le message
    Si une exception est lancée, ton programme s'arrête (enfin moi s'est le cas)
    Heu... non vu que je fais un catch...

    new [] instancie juste un tableau, mais en aucun cas les éléments de ton tableau
    new[] appelle le constructeur par défaut pour chaque élément du tableau.

    si tu veux tester si un élément de ton tableau à bien été alloué, tu dois faire le test un par un pour chaque élément de ton tableau.

    new[] alloue un seul bloc contiguë en mémoire, l'allocation se fait en une seule fois et échoue ou réussie.
    Soit tout le tableau est alloué, soit il ne l'est pas.

    Tu peux toujours, si tu souhaite que le tableau soit libéré dans n'importe quel cas, utiliser quelque chose comme ceci :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    int main(void)
    {
          std::unique_ptr<Foo[taille]> ptr;
         try {
               ptr = std::make_unique<Foo[taille]>();
         } catch (int)
         {
                std::cout << ptr << std::endl;
         }
    }
    Totalement HS ici.

  4. #4
    Membre chevronné Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Points : 2 160
    Points
    2 160
    Par défaut
    Pour moi la question ne se pose pas vraiment, si new échoue, ptr n'est pas modifié donc, tu ne peux pas faire de delete toi-même dessus.

    Sinon, voici une piste sur Can I throw an exception from a constructor? From a destructor? :
    You should throw an exception from a constructor whenever you cannot properly initialize (construct) an object. There is no really satisfactory alternative to exiting a constructor by a throw.

  5. #5
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Citation Envoyé par Ehonn Voir le message
    Pour moi la question ne se pose pas vraiment, si new échoue, ptr n'est pas modifié donc, tu ne peux pas faire de delete toi-même dessus.
    Oui, c'est ce que j'ai dit dans mon premier post.

    Je veux juste savoir ce que dit la norme à ce sujet.

    ?
    Je ne comprend pas pourquoi tu me montre ce lien.

  6. #6
    Membre à l'essai
    Inscrit en
    Janvier 2014
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Janvier 2014
    Messages : 5
    Points : 20
    Points
    20
    Par défaut
    Oui, new[] va tout supprimer

    Une solution est de faire un allocation sans appel de constructeur (par exemple avec malloc) puis de faire un placement new pour appeler le constructeur sur chaque élément. Regarde les sources de vector, je crois qu'il fait comme ça. Par contre, c'est une technique bas niveau et peu sécurisée, à encapsuler dans un classe RAII

  7. #7
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Citation Envoyé par Blainey Voir le message
    Oui, new[] va tout supprimer

    Une solution est de faire un allocation sans appel de constructeur (par exemple avec malloc) puis de faire un placement new pour appeler le constructeur sur chaque élément. Regarde les sources de vector, je crois qu'il fait comme ça. Par contre, c'est une technique bas niveau et peu sécurisée, à encapsuler dans un classe RAII
    Donc ensuite pour libérer, j'appelle explicitement le constructeur puis je libère avec free() ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Foo * myTab = malloc(...);
    for(...)
          new(myTab + i) Foo;
    //...
    for(...)
          myTab[i].~Foo();
    free(myTab);
    Très intéressante comme idée. .

    Je vais essayer de mon plonger dans la norme pour la première partie de ma question .

  8. #8
    Membre à l'essai
    Inscrit en
    Janvier 2014
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Janvier 2014
    Messages : 5
    Points : 20
    Points
    20
    Par défaut
    Citation Envoyé par N3797
    5.3.4 New

    8 A new-expression may obtain storage for the object by calling an allocation function (3.7.4.1). If the
    new-expression terminates by throwing an exception, it may release storage by calling a deallocation func-
    tion (3.7.4.2). If the allocated type is a non-array type, the allocation function’s name is operator new and
    the deallocation function’s name is operator delete. If the allocated type is an array type, the allocation
    function’s name is operator new[] and the deallocation function’s name is operator delete[].
    La norme ne distingue pas généralement de comportement différent pour new et new[], elle parle de "allocation function"

  9. #9
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Effectivement, la norme garantie la libération de la mémoire :

    20 If any part of the object initialization described above terminates by throwing an exception, storage has been obtained for the object, and a suitable deallocation function can be found, the deallocation function is
    called to free the memory in which the object was being constructed, after which the exception continues to propagate in the context of the new-expression. If no unambiguous matching deallocation function can be
    found, propagating the exception does not cause the object’s memory to be freed.

    Merci pour ton aide .

  10. #10
    Membre à l'essai
    Inscrit en
    Janvier 2014
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Janvier 2014
    Messages : 5
    Points : 20
    Points
    20
    Par défaut
    À lire : Exception Safety: Concepts and Techniques

    L'idée dans vector est de séparer l'allocation dans vector_base (qui au final fonctionne comme capsule RAII pour la gestion de la mémoire) et l'initialisation dans vector (appelle des constructeurs, des fonctions "Uninitialized storage" http://en.cppreference.com/w/cpp/memory comme uninitialized_fill_n - utiles pour éviter d'avoir à appeler trop souvent les constructeurs, en appelant une fois le constructeur puis en copiant l'objet initialisé - ou uninitialized_copy_n - pour copier les données sans avoir besoin de faire un appel au constructeur par défaut)

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

Discussions similaires

  1. designer VS2008 exception alors que build fonctionne
    Par Golzinne dans le forum Silverlight
    Réponses: 2
    Dernier message: 01/09/2010, 16h37
  2. Cumuler 2 emplois : que dit la loi?
    Par Baldy dans le forum Droit du travail
    Réponses: 10
    Dernier message: 28/08/2010, 12h59
  3. Réponses: 8
    Dernier message: 13/05/2009, 18h18
  4. Réponses: 2
    Dernier message: 13/06/2008, 16h34
  5. [C#]Comment eviter Exception pendant que programme en pause?
    Par Revan012 dans le forum Windows Forms
    Réponses: 11
    Dernier message: 11/03/2006, 03h05

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