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 :

delete void*


Sujet :

C++

  1. #1
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut delete void*
    Bonjour,

    je viens de remarquer un warning dans xCode : deleting 'void*' is undefined.

    Donc à l'execution, il ne delete rien du tout c'est ça ?

    Ca m'embete car je ne sais pas trop comment liberer les ressources allouees.

    En gros j'ai une partie du code haut niveau qui fait

    switch ()
    case:
    new truc.
    case
    new autretruc

    et ensuite objet->stocker((void*)machin);

    Je veux juste stocker un pointeur vers l'un des trucs instancié dans un objet qui a priori ne connait pas le type du truc qu'il va recevoir.

    Le soucis est dans le destructeur de l'objet ou je fait delete truc.

    Comment faire ?

  2. #2
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    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 296
    Par défaut
    Citation Envoyé par NiamorH
    Comment faire ?
    Programmer en C++ ?
    Pourquoi tu ne ferais pas dériver toutes tes classes d'un IStockable vu que tu veux stocker tes objets et les détruire polymorphiquement ?
    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
    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
    Par défaut
    Utiliser delete avec un type différent de celui utilisé avec new est un comportement indéfini, sauf si le type utilisé avec delete est une base du type utilisé avec new et si le destructeur est virtuel.

    Pour ton truc, tu peux utiliser malloc/free, qui n'ont pas cette restriction.

  4. #4
    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,
    Citation Envoyé par loufoque
    Utiliser delete avec un type différent de celui utilisé avec new est un comportement indéfini, sauf si le type utilisé avec delete est une base du type utilisé avec new et si le destructeur est virtuel.

    Pour ton truc, tu peux utiliser malloc/free, qui n'ont pas cette restriction.
    malloc et free n'ont peut etre pas cette restriction, mais par contre, ils en ont d'autres (et principalement celle de ne pas appeler automatiquement le constructeur/destructeur)...

    N'oublions quand meme pas que l'opérateur new (d'origine) effectue en réalité trois actions distinctes, alors que malloc ne fait jamais que l'allocation de la mémorie

    A titre personnel, je préférerais me rallier à la proposition de Luc: créer une hiérarchie de classes pour les différents objets à stocker, et ce, d'autant plus que cela permettra la mise en oeuvre d'un polymorphisme dont l'utilité risque d'apparaitre très rapidement (meme en ayant si peu d'informations )

    Par contre, NiamorH, pense à entourer les morceaux de code que tu présente de la balise code ([CODE ] ...[/CODE ](sans les espaces avant le bracket fermant) ou en cliquant sur le bouton "#" en haut du formulaire)

    Cette balise fournit une certaine coloriation synthaxique et maintient la mise en forme du code... et ce sont deux choses qui permettent de s'y retrouver bien plus facilement
    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 éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    en fait truc est une structure, pas une classe, donc la restriction dont tu me parle pour free n'est pas si genante car les structures n'ont pas de destructeurs. Cela pourrait marcher ?

    voila un la fonction qui alloue la memoire pour la structure :

    ne regardez pas tout le code mais juste les bouts en rouge

    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    #pragma pack(push, 1)
    // structure pour l'entete de fichier tga
    typedef struct
    {
      uchar id_lenght;            // size of image id
      uchar colormap_type;        // 1 is has a colormap
      uchar image_type;           // compression type
    
      ushort cm_first_entry;       // colormap origin
      ushort cm_length;            // colormap length
      uchar cm_size;              // colormap size
    
      ushort x_origin;             // bottom left x coord origin
      ushort y_origin;             // bottom left y coord origin
    
      ushort width;                // picture width (in pixels)
      ushort height;               // picture height (in pixels)
    
      uchar pixel_depth;          // bits per pixel: 8, 16, 24 or 32
      uchar image_descriptor;     // 24 bits = 0x00; 32 bits = 0x80
    
    } tga_header_t;
    #pragma pack(pop)
    
    
    ///////////////////////////////////////////////////////////////////////////////////////
    //      Chargement TGA
    ///////////////////////////////////////////////////////////////////////////////////////
    /**
     * @brief Creation d'un objet Image au format TGA
     * @param pi Le pointeur image pour charger l'image
     * @return L'image cree
     */
    Image*
    Chargeur::creerTGA(PointeurImage* pi)
    {
      // l'image a retourner
      Image* im = 0;
      // l'entete a creer
      tga_header_t* header = (new tga_header_t);
      void * entete = (void*)header;
      // le colormap a creer si besoin PAS ENCORE OP
      uchar *colormap = 0;
      
      // le fichier a lire et sa taille
      FILE *fp;
      int taille;
      
      // pointeur vers le debut des donnees(entete) et sur le debut des infos pixels
      uchar* donnees = 0, *donneespixels = 0;
      
      // ouverture du fichier pointe
      fp = fopen (pi->getChemin(), "rb");
      if (!fp)
        {
          fprintf (stderr, "erreur: fichier non trouve ou bloque \"%s\"!\n", pi->getChemin());
          return 0;
        }
    
      // recuperation de la taille du fichier
      fseek(fp, 0, SEEK_END);
      taille = ftell(fp);
      fseek(fp, 0, 0);
      
      // allocation des donnees pour charger l'image
      donnees = new uchar[ taille ];
      if (!donnees)
        {
          fprintf (stderr, "erreur: pas assez de memoire pour charger l'image !\n");
          return 0;
        }
    	
      // lecture du fichier image d'une traite
      fread( donnees, sizeof(uchar), taille, fp);
    
      // fermeture du fichier
      fclose (fp);
      
      // on va lire l'entete jusqu'au donnees pixels, on incremente un des pointeur et l'autre restera au debut pour desallouer plus tard
      donneespixels = donnees;
      
      /////////////////////  lecture de l'entete ////////////////////////////
      header->id_lenght = (*(donneespixels++));
      header->colormap_type = (*(donneespixels++));
      header->image_type = (*(donneespixels++));
      
    
    #ifdef MACOSX
      // gestion du little endian sous Mac
      ushort tempshort;
      
      tempshort = (*(donneespixels++));
      header->cm_first_entry = (*(donneespixels++));
      header->cm_first_entry <<= 8;
      header->cm_first_entry += tempshort;
      tempshort = (*(donneespixels++));
      header->cm_length = (*(donneespixels++));
      header->cm_length <<= 8;
      header->cm_length += tempshort;
    #else
      header->cm_first_entry = (*(donneespixels+=2));
      header->cm_length = (*(donneespixels+=2));
    #endif  
      
      header->cm_size = (*(donneespixels++));
      
    #ifdef MACOSX
      tempshort = (*(donneespixels++));
      header->x_origin = (*(donneespixels++));
      header->x_origin <<= 8;
      header->x_origin += tempshort;
      tempshort = (*(donneespixels++));
      header->y_origin = (*(donneespixels++));
      header->y_origin <<= 8;
      header->y_origin += tempshort;
      tempshort = (*(donneespixels++));
      header->width = (*(donneespixels++));
      header->width <<= 8;
      header->width += tempshort;
      tempshort = (*(donneespixels++));
      header->height = (*(donneespixels++));
      header->height <<= 8;
      header->height += tempshort;
    #else
      header->x_origin = (*(donneespixels+=2));
      header->y_origin = (*(donneespixels+=2));
      header->width = (*(donneespixels+=2));
      header->height = (*(donneespixels+=2));
    #endif
      
      header->pixel_depth = (*(donneespixels++));
      header->image_descriptor = (*(donneespixels++));
      
    
      // lecture du colormap si besoin
      if (header->colormap_type)
        {
          // NOTE: color map is stored in BGR format
          colormap = (donneespixels+=header->cm_length * (header->cm_size >> 3));
    	  fprintf(stderr,"attention colormap %d\n",(*donneespixels));
        }
    	
    #if defined DEBUG_FORMAT
      fprintf(stderr, "%d %d %d %d\n",header->colormap_type, header->image_type, header->pixel_depth, header->image_descriptor);
    #endif
    
      // creation d'une image
      im = new Image(header->width,header->height);
      // passage des donnees utiles
      im->setDonnees(donneespixels, donnees, entete, code_format_tga);
    
      return im;
    }
    
    Image::~Image(void)
    {
      if (m_donnees != 0)
        delete [] m_donnees;
     
      if (m_entete != 0)
        delete m_entete;
    	 
    #if defined DEBUG_TAMPON_IMAGE
      fprintf(stderr,"Destructeur Image\n");
    #endif
    }

  6. #6
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    en fait truc est une structure, pas une classe, donc la restriction dont tu me parle pour free n'est pas si genante car les structures n'ont pas de destructeurs
    Pas vraiment non. Une structure est une classe, à quelques différences près énoncées dans la FAQ.
    Ce qui fait qu'ici tu n'as pas besoin de destructeur, c'est que tes données membres sont toutes de type primitif (tu as donc ce qu'on appelle une structure POD -- plain old data).

    A part ça, je ne comprends pas comment ton image va exploiter ton en-tête sous forme de void*. D'ailleurs pourquoi en a-t-elle besoin ?

  7. #7
    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
    Citation Envoyé par NiamorH
    en fait truc est une structure, <snip>
    Sais tu qu'en C++, une classe et une structure sont quasiment équivalente

    Seul la visibilité par défaut des membres, méthodes et héritage diffère entre les deux...

    Rien ne t'empecherait donc, par exemple, de mettre un constructeur et un destructeur, ainsi qu'une méthode "load()" et une méthode "unload()"...

    Ceci dit, à de nombreux points de vue, le code que tu fournis est beaucoup plus du C que du C++ (utilisation de typedef struct, de FILE*, de fopen, de fprintf etc...)
    [EDIT] grilled
    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

  8. #8
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    C'est vrai, la raison a cela est qu'il s'agit d'une partie critique de mon appli.
    Je dois lire et instancier 25 images par secondes et les deleter aussi sec apres affichage. Je tenais à eviter de passer par des structures de donnees trop lourdes avec heritage qui aurait je pense ralenti considerablement le process. C'est pourquoi la classe Image ne contient que des donnees brutes non decodees. Le decodage se fait dans un autre thread qui affiche desuite via OpenGL sans restocker les donnees dans une structure plus complexe.

    Maintenant en y reflechissant, cela vaudrait peut etre le coup pour cette petite entete de faire une classe abstraite dont heritera chaque format d'entete TGA tiff etc.. Peut etre que je perdrais pas trop en rapidité, c'est a tester.

    Mais plus j'y pense, plus j'ai envie de faire dans mon destructeur d'image :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    if (entete != 0)
    switch (code_format)
    {
      case tga:
        tga_header_t* h = (tga_header_t*)entete;
        delete h;
    }
    non ?

  9. #9
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Je ne comprends toujours pas pourquoi tu as besoin de l'en-tête après chargement. Une fois décodé, une image c'est ni plus ni moins un tableau de pixels non ? Pourquoi l'image devrait se trimballer les informations relatives au format de fichier avec elle ?

    Sinon concernant le switch suivi d'un cast barbare pour la destruction, ce sera pas plus efficace qu'un appel de fonction virtuelle.

  10. #10
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Les donnees ne sont pas decodees dans l'image, elles sont brutes comme elles etaient dans le fichier tga.
    Ma classe image, ici, n'est pas une structure haut niveau qui permet l'acces a chaque pixel selon un x et un y. C'est juste un espace de stockage des donnees brutes.
    Ces 'images' sont lues dans un thread dédié a la lecture de fichier et placees dans un tampon d'image (une deque).
    Un autre thread dédié a l'affichage va depiler petit a petit le tampon image, recuperer les donnees brutes et l'entete, et, selon le format, va appeller une certaine fonction de decodage adaptee (analyse ici de ma structure entete pour savoir si l'image est 32 24 16 bits etc...) qui affiche directement avec OpenGL sans stocker les valeurs des pixels dans une autre classe intermediaire.
    Les images sont ensuites detruites.

  11. #11
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Dans ce cas je pense que tu peux construire une hiérarchie pour tes images : image_tga, image_png, etc... et n'utiliser que des fonctions virtuelles pour t'abstraire du type réel. Niveau performance ça ne devrait pas avoir un impact notable, de toute façon il faut le faire alors void* + id ou fonctions virtuelles, il n'y a pas grande différence.

  12. #12
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Alors ce n'est pas l'image qu'il faut que je fasse deriver mais la structure entete.

    Comme ca dans image j'aurai maintenant un pointeur vers un Entete* et lors de l'instanciation je ferrais new EnteteTGA et le delete Entete sera ok avec un destructeur virtuel.

    Je vais faire des tests demain pour voir si le passage de la structure à une classe polymorphe induit une perte notable de performances.

    Si c'est le cas je ferrai un cast barbare (pas tant que ça si ?) dans le destructeur.

  13. #13
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    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 296
    Par défaut
    Citation Envoyé par NiamorH
    Si c'est le cas je ferrai un cast barbare (pas tant que ça si ?) dans le destructeur.
    Et avant de faire le cast, tu feras combien de if ? -> O(n).
    vtbl -> O(1)

    Tu es en plein la question du coût illusoire du polymorphisme : si tu as besoin de prendre une décision à l'exécution, alors une indirection via la vtbl n'est pas plus chère que les autres solutions à base de if et autres tableaux de fonctions.

    Prix qui est d'ailleurs complètement négligeable comparé à l'allocation que tu fais déjà.
    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...

  14. #14
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    c'est simple je vais tester les deux methodes et voir si il y a des differences.

    si pas de difference j'opterais pour le polymorphisme plus elegant.

Discussions similaires

  1. [thinking in C++] delete sur void *
    Par exhortae dans le forum C++
    Réponses: 2
    Dernier message: 20/04/2008, 11h59
  2. delete sur un void*
    Par Biosox dans le forum C++
    Réponses: 8
    Dernier message: 07/11/2007, 17h47
  3. [requête] DELETE + SELECT
    Par doohan dans le forum Requêtes
    Réponses: 6
    Dernier message: 07/07/2003, 12h27
  4. [langage] delete de fichier
    Par lolive dans le forum Langage
    Réponses: 2
    Dernier message: 24/04/2003, 15h04
  5. TRaduction C++ => Delphi VOID ??
    Par escafr dans le forum Langage
    Réponses: 6
    Dernier message: 20/02/2003, 10h39

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