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

Livres C++ Discussion :

Erreur dans le livre Mieux programmer en C++?


Sujet :

Livres C++

  1. #1
    Membre du Club
    Homme Profil pro
    Inscrit en
    Février 2012
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Février 2012
    Messages : 7
    Par défaut Erreur dans le livre Mieux programmer en C++?
    Bonjour,

    J'ai été assez étonné de lire dans le livre "Mieux programmer en C++" a la page 30:

    http://dut.proced90.com/Documentatio...20en%20c++.pdf

    2.
    Il n’y a pas de risque de fuites mémoires.
    Détaillons en effet ce qui se passe en cas
    de génération d’exception : si l’opérateur
    new()
    lance une exception
    bad_alloc
    , comme
    le tableau d’objets
    T
    n’a pas encore été alloué, il n’y a donc pas de risque de fuite ; si la
    construction d’un des objets
    T
    alloué échoue, le destructeur de
    Stack
    est automatique-
    ment appelé (du fait qu’une exception a été générée au cours de l’exécution de
    Stack::Stack
    ), ce qui a pour effet d’exécuter l’instruction
    delete[]
    , laquelle effectue
    correctement la destruction et la désallocation des objets
    T
    ayant déjà été alloués.
    Hors lorsqu'une exception est lancé dans un constructeur l'objet n'est pas construit et le destucteur ne peu pas être appelé...
    Je ne comprend pas ce que l'auteur a voulu dire?

  2. #2
    Membre Expert
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Par défaut
    Il me semble que quand une exception est lancée au cours d'un constructeur, les membres dont le constructeur est déjà appelé ont leur destructeur appelé (dans l'ordre inverse des constructeurs).
    Par contre, concernant l'allocation dynamique, il faut gérer soit-même vu qu'en effet le destructeur n'est pas appelé
    c'est décrit dans la FAQ ici.

  3. #3
    Membre Expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Par défaut
    Oui il ne faut pas oublier que si un objet est construit, alors son destructeur sera appele, meme si c'est un objet membre d'un autre objet!

    Donc en gros

    class K
    {
    A a;
    B b;
    C c;
    K() { throw 42; }
    };



    Au moment du throw, a b et c sont construits donc ils seront deconstruits. C'est K qui n'est pas construit au moment du throw. Si a ou b ou c a alloue quelque chose, il sera desalloue.

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

    Informations professionnelles :
    Activité : aucun

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

    En gros, il faut savoir que le risque de fuite de mémoire survient lorsqu'on a recours à l'allocation dynamique de celle-ci.

    Lorsque tu déclares un membre par valeur (pour vsize_ ou pour vused_ dans l'exemple), il n'y a strictement aucune raison qu'une exception ne soit lancée.

    Le seul moment où il y a effectivement un risque qu'une exception soit lancée survient au moment du
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     v_ = new T[vsize_]; // Allocation initiale
    il y aura alors une exception de type std::bad_alloc qui sera lancée, si et uniquement si... l'allocation dynamique de la mémoire échoue.

    Tel que le code est présenté, il n'y aurait donc en effet strictement aucun risque de fuite mémoire, parce qu'il n'y a aucune raison d'invoquer un delete sur le résultat d'une allocation dynamique qui a échoué

    Par contre, là où tu aurais un grand risque de fuite mémoire, c'est si le constructeur venait à faire plus d'une allocation dynamique.

    Par exemple, une classe proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class MaClass{
        public:
            MaClass(int i, int j):i(i),j(j){
                 first = new int[i]; // peut échouer!!!(*)
                 second = new int[j]; // peut aussi échouer!!!(**)
           }
        private:
            int i;
            int j;
            int * first;
            int * second;
    }
    Ou, pire encore une classe proche 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
    class Matrix{
        public:
            Matrix(int lines, int columns):lines(lines),columns(columns){
                 data = new int *[lines]; // peut échouer (*)
                 for(int i = 0;i<lines;++i){
                     data[i]=new int[columns]; //peut aussi échouer (à chaque passage 
                                               // dans la boucle!!!) (**)
                 }
            }
        private:
            int lines;
            int columns;
            int ** data;
    };
    vont potentiellement poser problème.

    Non pas au moment de la première allocation de mémoire (*) car, si elle échoue, l'exception bad_alloc est lancée, et, comme il n'y a pas eu d'allocation dynamique avant, il n'y a rien qui nécessite le recours à delete ou à delete[], mais bien au niveau de la deuxième allocation dynamique (**):

    En effet, si la deuxième allocation dynamique (**) échoue, il faut, avant de quitter le constructeur, veiller à libérer le résultat de la première (*), voir (dans le cas de la classe Matrix ) de toutes les exécutions de la boucles pour lesquelles l'allocation dynamique a réussi avant qu'une (qui peut etre tout aussi bien la première que la dernière... ou n'importe laquelle entre les deux ) ne vienne à rater, sans oublier, toujours, de libérer le résultat de la première(*)

    Enfin, bref, pour arriver à gérer correctement tous les cas, cela devient beaucoup plus compliqué
    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

  5. #5
    Membre Expert
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Par défaut
    Je suppose qu'on peut solutionner une partie du problème (une fois qu'on a envisagé les solutions pour restreindre l'allocation dynamique) en wrappant les pointeurs individuels dans des smart pointers, et les objets créés en masse dans des containers, ou le cas échéant dans des containers de smart-pointers?
    Dans ce cas on se ramène à des membres déclarés par valeur

  6. #6
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 394
    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 394
    Par défaut
    En effet. Tant que la classe ne gère pas manuellement la durée de vie de ces ressources, elle devrait être exception-safe.
    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
    Membre du Club
    Homme Profil pro
    Inscrit en
    Février 2012
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Février 2012
    Messages : 7
    Par défaut
    Effectivement alors lorsque l'allocation d'un tableau de classe avec new[] lance une exception std::bad_alloc les éléments déjà allouée du tableau sont libéré par la fonction new[]!

    Cependant le destructeur des éléments du tableau est appelé pour les éléments déjà construit mais pas le destructeur de la classe Stack!

    La fonction delete[] n'est au final jamais appelé dans l'exemple...

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Citation Envoyé par feidaykin Voir le message
    Effectivement alors lorsque l'allocation d'un tableau de classe avec new[] lance une exception std::bad_alloc les éléments déjà allouée du tableau sont libéré par la fonction new[]!

    Cependant le destructeur des éléments du tableau est appelé pour les éléments déjà construit mais pas le destructeur de la classe Stack!

    La fonction delete[] n'est au final jamais appelé dans l'exemple...
    En fait, le destructeur est juste un peu plus bas (mais n'intervient au final pas dans le problème), et delete[] est bel et bien appelé dedans

    La classe stack est exception safe de par le fait que, le destructeur n'a pas besoin d'être appelé si un exception survient, vu que c'est justement l'allocation de la seule ressource qui aurait besoin d'être libérée(v_) qui n'a pas pu se faire correctement.

    Par contre, même avec les destructeurs "qui vont bien", le fait d'avoir à gérer plus d'une allocation dynamique dans le constructeur fait que mes deux exemples ne sont pas exception safe

    Oupss, et au fait: Pour que tout se passe correctement, il faudrait aussi prévoir le constructeur par copie et l'opérateur d'affectation, selon la règle des trois grands, mais ca, c'est une autre histoire
    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

  9. #9
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Cela dit, dans un monde idéal, une classe ne gère pas deux ressources manuellement, vu qu'elle respecte la règle de la responsabilité unique…

  10. #10
    Membre Expert
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Par défaut
    Citation Envoyé par leternel Voir le message
    Cela dit, dans un monde idéal, une classe ne gère pas deux ressources manuellement, vu qu'elle respecte la règle de la responsabilité unique…
    Je suis pas sûr qu'on puisse aller jusqu'à 1 responsabilité=1 ressource, tout de même, on n'est pas au même niveau de granularité, non?

  11. #11
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 394
    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 394
    Par défaut
    À moins de faire des try/catch dans le constructeur pour libérer la première ressource dont on est directement responsable si la seconde foire, si.
    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.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Citation Envoyé par therwald Voir le message
    Je suis pas sûr qu'on puisse aller jusqu'à 1 responsabilité=1 ressource, tout de même, on n'est pas au même niveau de granularité, non?
    Ben, étant donné que c'est au niveau de l'allocation de la mémoire que se pose le problème, pourquoi pas

    Le fait d'avoir, par exemple, un patron de type "fabrique" qui crée les objets à la demande peut parfaitement être résistant aux exception, même si, à coté de cela, il y a une allocation dynamique de la mémoire au niveau de la collection qui devra maintenir une référence (enfin, un pointeur) vers les objets créés
    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

  13. #13
    Membre Expert
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Ben, étant donné que c'est au niveau de l'allocation de la mémoire que se pose le problème, pourquoi pas
    Ok, alors mettons que pour chaque ressource dynamique nous utilisons une classe (pas nécessairement custom, j'imagine qu'un smart pointer ou un container peut jour le rôle) pour gérer sa durée de vie de manière exception-safe.
    Par contre, le fait de déclencher l'instanciation ne sera pas sous le contrôle de ces classes RAII...pour remplir son rôle (même unique) une classe "C" peut avoir besoin de plus d'une ressource (dynamique ou non), que nous mettrons en place autant que possible au niveau de son constructeur afin que le constructeur nous livre un objet "en état de marche". Alors là la responsabilité de "décider" que les ressources naissent et éventuellement (si exception, ou en fin de vie de l'instance de "C") meurent est bien au niveau de "C". La classe de RAII de chaque ressource est responsable de la cohérence de son cycle de vie, mais le déroulement du cycle en question est bien sous le contrôle de quelque chose "de plus", à savoir la classe "C", non?

  14. #14
    Membre Expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Par défaut
    Si ta class C a des membres qui sont alloues dynamiquement, utilise des smart pointers ou autres classes gerant chacun de ces membres.

    En suivant cette regle, tu n'auras tout simplement jamais de fuite memoire, d'ou l'utilisation de smart pointer quand un objet detiens (a le droit de vie et de mort) sur un autre.

    C'est pas pour rien qu'il y a des unique_ptr et shared_ptr un peu partout dans du code c++ moderne. C'est parceque c'est bien la seule maniere d'avoir toute les garanties niveau memoire. (hors acces douteux)

  15. #15
    Membre Expert
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Par défaut
    Citation Envoyé par Klaim Voir le message
    Si ta class C a des membres qui sont alloues dynamiquement, utilise des smart pointers ou autres classes gerant chacun de ces membres.
    Hmmm...tu prêches un convaincu...
    Ma question portait plus sur la notion de responsabilité. Les smart pointers et containers servent à garantir la gestion de mémoire mais le droit de vie et de mort, justement, ce n'est pas eux qui l'ont, ils ne sont que le bourreau...

  16. #16
    Membre Expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Par défaut
    Le droit de vie et de mort qui EST la gestion de la memoire... (ou au moins une partie)

    Un smart pointer detiens un objet pointe, il peut le detruire donc il le detiens. En programation la detention (owning) veut dire que celuis qui detiens va detruire l'objet.
    Donc en gros, le smart pointer est bien le responsable de l'objet pointe, mais le responsable de ce smart pointer peut etre l'objet l'englobant si ce smart pointer est un membre.

    Ca fais une chaine de responsabilite qui corresponds exactement a l'ordre de destruction des objets.

    Meme si la memoire a ete alloue par un pool, et que tu utilises un smart_ptr pour gerer le moment ou le pool doit savoir que l'objet peut etre detruit et la memoire reutilisee, ca reviens a liberer la memoire pour l'utilisateur du pool (dont la responsabilite est la memoire pure et dure, tandis que le smart ptr a la responsabilite de la memoire correspondant a l'objet, une sorte de segmentation).

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    En fait, un smart pointer, c'est quoi

    Ce n'est qu'une classe (que tu vas manipuler par valeur) qui va "englober" ton pointeur et appeler automatiquement delete dessus au plus tard dans son destructeur.

    La classe unique_ptr de c++11 par exemple ressemblera à quelque chose comme
    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
     
    template <typename Type> //(*)
    class unique_ptr{
        public:
            using pointer_type = Type *;
            unique_ptr(unique_ptr const &)  = delete; // copie interdite
            unique_ptr& operator=(unique_ptr const & ) = delete ;// assignation intetrdite
            unique_ptr(pointer_type ptr = nullptr):ptr(ptr){}
            ~unique_ptr(){release();}
            pointer_type get(){return ptr;}
            void release(pointer_type newpointer = nullptr){
                delete ptr; // rappel: delete sur null ne fait rien
                ptr = newpointer;
            }
            bool valid() const{return ptr!=nullptr;}
        private:
            pointer_type ptr;
    };
    (*) en fait, il y a un deuxième paramètre template qui correspond au "deleter" (à l'objet qui s'occupera de libérer la mémoire allouée au pointeur), mais ce n'est encore qu'un détail

    Tu pourrais très bien l'utiliser sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main(){
        unique_ptr<int> obj(new int[64]);
        for(int i=0;i<64:++i){
            obj.get()[i] = i*i; //obj.get() == ptr[0]
        }
    } // obj est détruit: ~obj est invoqué; release(nullptr) est appelé, delete ptr est invoqué(*)
    (*)C'est, justement, parce qu'il faudrait pouvoir invoquere delete[] sur ptr qu'il y a un deuxième paramètre template

    Ce qui importe, c'est que, à partir du moment où tu va manipuler cette classe par valeur, la durée de vie de chacune des instances de cette classe sera parfaitement connue:

    depuis le moment de sa déclaration jusqu'à l'accolade fermante de la portée où elle est déclarée lorsqu'il s'agit d'une variable de fonction
    depuis le moment où le constructeur est appelé (dans l'ordre de déclaration des membres) dans le constructeur de la classe qui l'utilise au moment où son destructeur est appelé (dans l'ordre inverse de la déclaration des membres) dans le destructeur de la classe qui l'utilise.

    Ainsi, tu pourrais très bien avoir une classe prenant la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class MaClass{
        public:
            MaClass(Type1* one, Type2 * two):one(one),two(two){}
        private:
            unique_ptr<Type1> one;
            unique_ptr<Type2> two;
    };
    qui, bien que manipulant deux unique_ptr différents, n'occasionnerait pas de fuite mémoire.

    Pourquoi parce que la responsabilité de la durée de vie des ressources allouée respectivement à one et two a été déléguée à la classe unique_ptr.

    Tout ce qu'il faut, pour assurer la résistance aux exception avec cette classe, c'est de s'assurer que "tout se passera correctement" si une exception survient au moment de l'allocation de la mémoire pour one et pour two.

    Cette classe pourrait parfaitement être utilisée de manière exception safe sous une forme proche 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
    MaClass * foo(/* les paramètres uties */){
        toujours le même principe: delete sur nullptr ne fait rient
        MaClass * ret = nullptr;
        Type1 * one = nullptr;
        Type2 * two = nullptr;
        try{
             one= new Type1(/* paramètres nécessaires */);
             two= new Type2(/* paramètres nécessaires */);
             ret = new MaClass(one, two);
        }
        catch(std::bad_allloc & e){
            /* ne détruit que one et two car, dans le pire des cas, si on passe ici,
             * c'est que l'allocation dynamique de ret a échoué
             * 
             * Dans tous les autres cas, delete sur nullptr nous garanti que rien ne
             * sera fait
             */
             delete one;
             delete two;
        }
        retrurn ret;
    }
    Cette fonction ne provoquera aucune fuite mémoire et sera résistante aux exceptions, bien que cela implique (eh, tout a un prix en informatique ) qu'il faille vérifier la validité de l'adresse renvoyée par cette fonction (car elle peut renvoyer nullptr)

    Tu pourrais même parfaitement placer des unique_ptr dans une collection (il faudra sans doute utiliser la sémantique de mouvement pour ce faire, vu que la classe est non copiable ), et tu n'auras pas de problème de fuite mémoire:

    Toutes les instances de unique_ptr qui existent encore au plus tard au moment où la collection sera détruite le seront de manière automatique, tout comme chaque instance supprimée de la collection aura pour résultat de libérer la mémoire allouée à la ressource qu'elle contient
    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

Discussions similaires

  1. Où en êtes-vous dans le livre "Apprenez à programmer en JAVA" ?
    Par mike1313 dans le forum Débuter avec Java
    Réponses: 6
    Dernier message: 20/07/2014, 14h19
  2. [Livre] Mieux programmer en Java - 68 astuces pour optimiser son code
    Par MarieKisSlaJoue dans le forum Général Java
    Réponses: 0
    Dernier message: 01/07/2014, 15h00
  3. Tri shell : erreur dans le livre bac info ?
    Par adel_info dans le forum Pascal
    Réponses: 13
    Dernier message: 12/11/2009, 09h43

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