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 :

Opérateur delete[] sur un non tableau


Sujet :

Langage C++

  1. #1
    Membre actif Avatar de Robxley
    Homme Profil pro
    Docteur ingénieur traitement d'image
    Inscrit en
    Mai 2009
    Messages
    158
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Docteur ingénieur traitement d'image

    Informations forums :
    Inscription : Mai 2009
    Messages : 158
    Points : 228
    Points
    228
    Par défaut Opérateur delete[] sur un non tableau
    Bonjour,

    J'ai juste une question sur le fonctionnement de l'opérateur delete[].
    Est il possible d'utiliser l'opérateur delete[] sur une variable qui a été alloué par new, (et non l'opérateur tableau new[]).

    Un petit exemple de code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int *ptr;
     
    if (condition1) ptr = new int;
    else ptr = new int[10];
    /*j'utilise mon ptr ds mon pogramme*/
     
    delete[] ptr;
    Donc est ce que dans le cas ou la condition1 est vérifiée il est autorisé d'appeller delete[] sur ptr ?

    Alors vous me direz pour régler le problème il suffit de faire ptr = new[1] pour ne plus se poser la question, mais c'est plus une question de curiosité que de solution algorithmique.
    Rien ne sert de courir, mieux vaut partir à point. Programmer aussi d'ailleurs.
    Surtout, mais surtout pas d’astuces !
    Pas de bras, pas de chocolat. Les deux mains sur le clavier.

  2. #2
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    delete[] sur un objet alloué avec new donne un comportement indéfinie.
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  3. #3
    Membre actif Avatar de Robxley
    Homme Profil pro
    Docteur ingénieur traitement d'image
    Inscrit en
    Mai 2009
    Messages
    158
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Docteur ingénieur traitement d'image

    Informations forums :
    Inscription : Mai 2009
    Messages : 158
    Points : 228
    Points
    228
    Par défaut
    Oki, merci pour la réponse.

    Je me suis un peu renseigné, si j'ai bien compris lors de l'appel à new[] il y a une sauvegarde du nombre n d'éléments lors de l'allocation mémoire, ce même nombre n étant utilisé par delete[] par la suite. Donc il semblerait que lors de l'appel de new[]/delete[] il y a un stockage de ce n qui coute de l'espace mémoire ? ce n est stocker ou et comment ?

    et ça voudrait dire que :

    int *i = new int; demande moins d'espace mémoire que :
    int *i = new int[1];

    Certe la différence en espace mémoire doit être minimum mais ceci peut avoir de l'importance dans le cas ou le système est limité en espace mémoire (système embarqué par exemple);
    Rien ne sert de courir, mieux vaut partir à point. Programmer aussi d'ailleurs.
    Surtout, mais surtout pas d’astuces !
    Pas de bras, pas de chocolat. Les deux mains sur le clavier.

  4. #4
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par Robxley Voir le message
    Oki, merci pour la réponse.

    Je me suis un peu renseigné, si j'ai bien compris lors de l'appel à new[] il y a une sauvegarde du nombre n d'éléments lors de l'allocation mémoire, ce même nombre n étant utilisé par delete[] par la suite. Donc il semblerait que lors de l'appel de new[]/delete[] il y a un stockage de ce n qui coute de l'espace mémoire ? ce n est stocker ou et comment ?

    et ça voudrait dire que :

    int *i = new int; demande moins d'espace mémoire que :
    int *i = new int[1];

    Certe la différence en espace mémoire doit être minimum mais ceci peut avoir de l'importance dans le cas ou le système est limité en espace mémoire (système embarqué par exemple);
    Ce sont des détails d'implémentations. Tu peux avoir des gestions mémoires complètement différentes où par exemple, n serait stocké tout le temps, ou encore dans lesquels les blocs mémoires ont toujours la même taille, etc. Tu ne peux t'appuyer sur un détail d'implémentation particulier. Ce que te dis le langage entre autre :
    new [] -> delete []
    new -> delete
    si tu croises -> comportement indéfini.
    Les garanties de var = new[N] :
    -> var[0], var[1], ... var[N-1] sont des objets valides
    -> &var[0] + i == &var[i] (i<N)

  5. #5
    Membre averti
    Profil pro
    professeur des universités à la retraite
    Inscrit en
    Août 2008
    Messages
    364
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : professeur des universités à la retraite

    Informations forums :
    Inscription : Août 2008
    Messages : 364
    Points : 439
    Points
    439
    Par défaut
    Chez moi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include <iostream>
    using namespace std;
     
    int main()
    {
      int tab[]={1};
      cout << sizeof(int) << ' ' << sizeof(tab);
    }
    donne


  6. #6
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Un tableau statique n'est pas pareil qu'un tableau dynamique. Il n'y a pas de correspondance new/delete. On ne peut pas comparer.

  7. #7
    Membre averti
    Profil pro
    professeur des universités à la retraite
    Inscrit en
    Août 2008
    Messages
    364
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : professeur des universités à la retraite

    Informations forums :
    Inscription : Août 2008
    Messages : 364
    Points : 439
    Points
    439
    Par défaut
    Mon exemple n'était pas pertinent car la question portait sur new/delete[] (et sur le surplus de mémoire qu'ils impliquent, pas sur le tableau lui-même), mais il me semble par ailleurs que le tableau créé par new est tout ce qu'il y a de statique non ? (au sens où leur taille est invariable), ou bien je ne comprends pas le sens de "tableau statique" ?

  8. #8
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Le problème du vocabulaire est qu'on l'emploi parfois un peu rapidement sans en partager la sémantique
    J'ai utilisé les termes statiques et dynamiques dans les sens suivants - peut être mal à propos d'une façon générale mais qui m'ont paru approprié dans ce cas :
    -> tableau statique : Type var[] ;
    -> tableau dynamique : Type var=new[].
    Dynamique n'étant pas tant du au fait qu'on peut modifier dynamiquement la taille d'un tableau existant, mais plutôt qu'on définit sa taille au moment de l'exécution et qu'on obtient un emplacement dynamiquement.

  9. #9
    Membre actif Avatar de Robxley
    Homme Profil pro
    Docteur ingénieur traitement d'image
    Inscrit en
    Mai 2009
    Messages
    158
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Docteur ingénieur traitement d'image

    Informations forums :
    Inscription : Mai 2009
    Messages : 158
    Points : 228
    Points
    228
    Par défaut
    Oki oki, merci pour toutes ces réponses.

    Quoi qu'il en soit j'utiliserai new avec delete, et le grand frère du 1er avec le grand frère du 2nd, new[] -> delete[]
    Rien ne sert de courir, mieux vaut partir à point. Programmer aussi d'ailleurs.
    Surtout, mais surtout pas d’astuces !
    Pas de bras, pas de chocolat. Les deux mains sur le clavier.

  10. #10
    Membre averti
    Avatar de Chatanga
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    211
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 211
    Points : 346
    Points
    346
    Par défaut
    En pratique, j'ai toujours relevé le même comportement pour l'instruction new[] : un mot mémoire est utilisé en amont du bloc mémoire retourné (par la méthode new[] qui est redéfinissable de différentes manières) pour stocker la taille du tableau ssi la classe instanciée comporte un destructeur. Le seul but de stocker la taille est en effet d'appeler le destructeur pour chaque instance du tableau (et c'est pourquoi appeler delete[] sur un bloc mémoire alloué par new est casse-gueule).

    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    tab = new MaClasse[5]; // sizeof(MaClasse) == 4
     
    |<------------ new[](5*4+1) ------------->|
     
    |5|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
      ^       ^       ^       ^       ^
                      |
                    tab[2]

    Mais il est sans doute vrai que la norme du C++ ne spécifie pas la manière dont un compilateur doit procéder dans ce domaine.

  11. #11
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par Chatanga Voir le message
    En pratique, j'ai toujours relevé le même comportement pour l'instruction new[] : un mot mémoire est utilisé en amont du bloc mémoire retourné (par la méthode new[] qui est redéfinissable de différentes manières) pour stocker la taille du tableau ssi la classe instanciée comporte un destructeur. Le seul but de stocker la taille est en effet d'appeler le destructeur pour chaque instance du tableau (et c'est pourquoi appeler delete[] sur un bloc mémoire alloué par new est casse-gueule).
    Salut,
    J'ai travaillé sur des plate-formes embarquées dans lesquelles les allocations fonctionnaient par pool de blocs mémoires de taille fixe (suivant le pool). Donc new T[1] et new T retournait un bloc de même taille. Quand au fait de savoir si le nombre d'éléments est avant, après ou ailleurs, j'avoue ne pas avoir comparé différents compilo pour voir les différences. Cela reste un détail d'implémentation sur lequel il est dangereux de tirer de quelconques conclusions.

  12. #12
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Sans compter que new peut être surchargé pour utiliser un autre allocateur. (plus perf pour les petits objets par exemple...)
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Pire, il y a des implémentations où le comportement de new[] varie selon que le type alloué soit POD ou non...
    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.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par ptyxs Voir le message
    Chez moi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include <iostream>
    using namespace std;
     
    int main()
    {
      int tab[]={1};
      cout << sizeof(int) << ' ' << sizeof(tab);
    }
    donne

    Il faut en plus attirer l'attention sur le fait que tab représente en réalité "l'adresse du premier élément du tableau (de tab[0])"...

    Or, un pointeur est une variable numérique (non signée) dont la taille (en nombre de bits / bytes) est... suffisante pour représenter l'ensemble des adresses mémoires utilisée.

    En fonction du processeur utilisé (32 ou 64 bits), du systeme d'exploitation (idem) et du compilateur (64 bits compliant ou non) utilisé, tu peux très bien avoir des valeurs différentes, un int pouvant toujours être représenté sous la forme de 4 bytes (bien que rien ne l'oblige), mais un pointeur pouvant, par exemple, etre représenté sous la forme de... 8 byte (équivalent à unsigned long ou unsigned long long), toujours, sans obligation aucune.
    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

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Attention, sizeof(tab) sera toujours sizeof(int) ici:
    Le tableau est implicitement convertible en pointeur, mais reste un tableau; tout comme &tab n'est pas de type int**, mais de type int(*)[4]...
    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.

  16. #16
    screetch
    Invité(e)
    Par défaut
    new int[] n'a pas besoin de stocker le nombre d'éléments, c'est le cas seulement pour les classes qui ont un destructeur qui doit etre appelé. le role de ce petit nombre est de savoir combien de destructeurs doivent etre appelés.

    si l'on redéfinit l'opérateur new[] on peut s'en rendre compte :
    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
    #include <new>
    #include <cstdio>
     
    class Test1
    {
        int m_pad;
    public:
        void* operator new[](size_t size) { printf("size : %d\n", size); return ::operator new(size); }
        void  operator delete[](void* ptr) { return ::operator delete(ptr); }
    };
     
    class Test2 : public Test1
    {
    public:
        ~Test2() { printf("non trivial\n"); }
    };
     
     
    int main()
    {
        Test1 *tests1 = new Test1[1];
        Test2 *tests2 = new Test2[1];
        delete[] tests2;
        delete[] tests1;
        return 0;
    }
    renvoie 4 pour un Test1 et 12 pour un Test2 (8 octets sur ma machine 64 bits)


    [edit] en fait c'est deja ce qu'a dit chatanga

  17. #17
    Membre averti
    Profil pro
    professeur des universités à la retraite
    Inscrit en
    Août 2008
    Messages
    364
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : professeur des universités à la retraite

    Informations forums :
    Inscription : Août 2008
    Messages : 364
    Points : 439
    Points
    439
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Il faut en plus attirer l'attention sur le fait que tab représente en réalité "l'adresse du premier élément du tableau (de tab[0])"...

    Or, un pointeur est une variable numérique (non signée) dont la taille (en nombre de bits / bytes) est... suffisante pour représenter l'ensemble des adresses mémoires utilisée.

    En fonction du processeur utilisé (32 ou 64 bits), du systeme d'exploitation (idem) et du compilateur (64 bits compliant ou non) utilisé, tu peux très bien avoir des valeurs différentes, un int pouvant toujours être représenté sous la forme de 4 bytes (bien que rien ne l'oblige), mais un pointeur pouvant, par exemple, etre représenté sous la forme de... 8 byte (équivalent à unsigned long ou unsigned long long), toujours, sans obligation aucune.
    En fait tab est ambigu : traité comme pointeur ou tableau selon le contexte, c'est bien un des inconvénients de ce type d'objets.
    sizeof(tab) donne bel et bien la taille du tableau et non du pointeur

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include <iostream>
    using namespace std;
     
    int main()
    {
      int tab[]={1,2,3,4,5,6};
      cout << sizeof(int) << ' ' << sizeof(tab);
    }
    donne chez moi


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

Discussions similaires

  1. delete sur un tableau d'objets dans destructeur
    Par Mihnea24 dans le forum Débuter
    Réponses: 6
    Dernier message: 05/12/2008, 22h42
  2. [C#] [FTP] Envoi et suppression fichier sur ftp NON ANONYME!
    Par djsbens dans le forum Windows Forms
    Réponses: 14
    Dernier message: 30/03/2005, 10h20
  3. [Debutant][Install][VS]erreur sur fichier non trouvé.
    Par silvermoon dans le forum DirectX
    Réponses: 4
    Dernier message: 16/07/2004, 20h59
  4. delete sur une vue: rule
    Par Bouboubou dans le forum PostgreSQL
    Réponses: 8
    Dernier message: 18/05/2004, 18h58
  5. [langage] random sur liste ou tableau
    Par martijan dans le forum Langage
    Réponses: 2
    Dernier message: 15/07/2003, 14h47

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