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 :

[C++] Libération de mémoire de void*


Sujet :

C++

  1. #1
    Expert confirmé
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Points : 4 388
    Points
    4 388
    Par défaut [C++] Libération de mémoire de void*
    Bonjour,

    Je suis confronté à un petit problème : j'utilise la librairie pthread pour gérer le multithreading (je n'ai pas accès à std::thread non supporté par mon compilateur) et je code en C++. Le prototype de la fonction callback qui fera le travail du thread est la suivante : void* callback(void* arg); et donc travaille sur des pointeurs génériques (void*).

    Le problème est que faire un delete sur un void* provoque un comportement indéfini d'après la documentation.

    Comment faire pour supprimer la mémoire alloué au paramètre "arg" si à un moment donné j'ai perdu la vraie nature de la classe que j'ai passé en paramètre ? Est ce que faire un free appelerait le destructeur de la classe ?

    Exemple : Soit une classe Dummy.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Dummy* d = new Dummy();
    pthread_t thread;
    pthread_create(&thread, callback, NULL, d);
     
    // et plus loin dans le programme dans une autre fonction je dois supprimer la mémoire allouée par "d" mais j'ai perdu le type réel du pointeur à savoir pointeur sur classe Dummy. Je ne peux donc pas caster et faire un delete après....
    Merci et bonne journée
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  2. #2
    Invité
    Invité(e)
    Par défaut
    Je ne suis pas expert mais pour la première question je dirais que si tu as perdu la nature de la classe passé en paramètre c'est mort, sauf si le compilateur insère des mécanisme permettant de ... (j'en doute fort), et pour la seconde question je dirais non, un free ne va pas appeler le destructeur.
    Mais pourquoi est ce que tu ne libères pas la mémoire aprés avoir appeler callback(), ex:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char *ptr = new char [256]; callback( ( void *)ptr); delete [] ptr;
    C'est plus sûr non?
    Dernière modification par LittleWhite ; 20/03/2016 à 19h51. Motif: Pas besoin de citer l'intégralité du message précédent

  3. #3
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 627
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 627
    Points : 10 551
    Points
    10 551
    Par défaut
    Citation Envoyé par Ratator Voir le message
    Mais pourquoi est ce que tu ne libères pas la mémoire aprés avoir appeler callback(), ex:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char *ptr = new char [256]; callback( ( void *)ptr); delete [] ptr;
    C'est plus sûr non?
    Peut-être parce que c'est une callback

    Par définition, une callback peut-être appelée à n'importe quel moment: à la fin ou au début d'un traitement, à la réception d'un événement ...

    La solution que je vois (mais il faut attendre les experts) c'est de rendre ce pointeur plus ou moins global: soit carrément global, soit encapsuler dans une classe qui contient que les données de l'application (AppData), soit dans la classe principale, soit ...

    Il faut le laisser vivre sa vie et lorsque c'est possible (*), vérifier son état et le détruire en conséquence.

    * -> Par d'exemple à la création d'un nouveau thread, après un pthread_join, à la fin du programme, ...

  4. #4
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Hello,

    Tu peux utiliser un type commun à tous tes arguments, et laisser l'héritage se charger de retrouver le type pour toi et appeler le bon dtor.

    Toutes les classes ont au moins 1 point commun : elles ont un dtor, ça fait une base correcte pour tes arguments.
    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 <iostream>
     
    struct Arg {
    	virtual ~Arg() = 0 { }
    };
     
    struct Dummy_0 : Arg {
    	~Dummy_0() { std::cout << "Dummy_0" << std::endl; }
    };
     
    struct Dummy_1 : Arg {
    	~Dummy_1() { std::cout << "Dummy_1" << std::endl; }
    };
     
    void foo(void *arg) {
    	Arg *a = reinterpret_cast<Arg*>(arg);
    	delete a;
    }
     
    int main() {
     
    	foo(reinterpret_cast<void*>(new Dummy_0));
    	foo(reinterpret_cast<void*>(new Dummy_1));
     
    	return 0;
    }

  5. #5
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

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

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    Est-ce que tu es vraiment obligé d'utiliser des pointeurs? Voici ce que j'aurais fait:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Dummy d;
    pthread_t thread;
    pthread_create(&thread, callback, NULL, static_cast<void*>(&d));

  6. #6
    Membre éprouvé Avatar de fenkys
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    376
    Détails du profil
    Informations personnelles :
    Âge : 56
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Octobre 2007
    Messages : 376
    Points : 1 054
    Points
    1 054
    Par défaut
    Citation Envoyé par darkman19320 Voir le message
    Est-ce que tu es vraiment obligé d'utiliser des pointeurs? Voici ce que j'aurais fait:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Dummy d;
    pthread_t thread;
    pthread_create(&thread, callback, NULL, static_cast<void*>(&d));
    Bonjour,

    La méthode que tu préconises est très mauvaise. Si après le pthread_create on sort du scope de d, d se detruit. Mais rien ne dit que la callback aura fini d'utiliser les données, rien ne dit qu'elle aura été appelée.

    Nous sommes en environnement multithread et que nous ne savons pas quand la fonction de callback aura utilisé la variable passée en paramètre. Il faut donc s'assurer que :
    - soit la destruction de cette variable est sous le contrôle de la callback
    -> en la détruisant elle même.
    -> en signalant qu'elle peut être détruite.
    - soit le thread appelant ne détruit la variable qu'une fois le thread appelé terminé (c'est à ça que sert pthread_join).
    Mais en aucun cas, le thread appelant ne doit détruire cette variable sans contrôle.

    Aspic, pour utiliser ton pointeur, ta callback doit connaitre son type exact. Donc a priori, tu doit pouvoir la détruire sans problème.

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 113
    Points : 32 958
    Points
    32 958
    Billets dans le blog
    4
    Par défaut
    Salut,

    y'a pas de magie, et faut pas avoir peur de faire un simple cast.
    Btw ton paramètre tu le récupères en void*, donc tu dois de toutes façons le cast pour l'utiliser dans ta callback.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  8. #8
    Expert éminent sénior

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 045
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Bas Rhin (Alsace)

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

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 045
    Points : 11 368
    Points
    11 368
    Billets dans le blog
    10
    Par défaut
    Pour les callbacks, j'ai l'habitude que le void * data soit un contexte d'appel, et je ne vois pas pourquoi ni comment tu pourrais avoir besoin de le détruire dans le callback...
    Peux-tu préciser ton contexte?
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

  9. #9
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

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

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    Citation Envoyé par fenkys Voir le message
    La méthode que tu préconises est très mauvaise. Si après le pthread_create on sort du scope de d, d se detruit. Mais rien ne dit que la callback aura fini d'utiliser les données, rien ne dit qu'elle aura été appelée.
    Il est vraiment que mon exemple est naïf. Je voulais plus porter ma question sur l'obligation d'utiliser des pointeurs plutôt que des objets (qui seraient stockés dans un objet qui resterai en vie pendant l'ensemble du programme et qui permettrait la création et la destruction de ces objets (une fois que ceux ci ne seraient plus nécessaires par le thread appelé par exemple)). Est-ce plus simple et/ou performant d'utiliser des pointeurs nus que de simples objets?

  10. #10
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 113
    Points : 32 958
    Points
    32 958
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par darkman19320 Voir le message
    Il est vraiment que mon exemple est naïf. Je voulais plus porter ma question sur l'obligation d'utiliser des pointeurs plutôt que des objets (qui seraient stockés dans un objet qui resterai en vie pendant l'ensemble du programme et qui permettrait la création et la destruction de ces objets (une fois que ceux ci ne seraient plus nécessaires par le thread appelé par exemple)). Est-ce plus simple et/ou performant d'utiliser des pointeurs nus que de simples objets?
    La différence entre un pointeur et... un pointeur ? Euh.. aucune ?
    On se moque de savoir où se trouve l'objet, dans la pile, heap ou quoi que ce soit. Tout ce qu'on demande c'est un pointeur vers un truc.
    Si un simple int suffit, tu n'as même pas besoin de créer quoi que ce soit, nullptr+x et x-nullptr et voilà tu as passé un int gratos !

    et je ne vois pas pourquoi ni comment tu pourrais avoir besoin de le détruire dans le callback...
    Et moi j'ai le plus souvent une struct bidon qui me sert à passer tous mes paramètres, dont certains créés pour l'occasion, à ma callback, et je ne vois pas comment ni pourquoi je ne devrais pas les détruire dans la callback.
    Elle l'utilise, puis le détruit, basta. Et je n'ai plus besoin de "m'assurer que mon objet existe suffisament longtemps pour que la callback ait le temps de l'utiliser". C'est le sien.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  11. #11
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Et moi j'ai le plus souvent une struct bidon qui me sert à passer tous mes paramètres, dont certains créés pour l'occasion, à ma callback, et je ne vois pas comment ni pourquoi je ne devrais pas les détruire dans la callback.
    Elle l'utilise, puis le détruit, basta. Et je n'ai plus besoin de "m'assurer que mon objet existe suffisament longtemps pour que la callback ait le temps de l'utiliser". C'est le sien.
    Merci de ne pas appeler ça une callback. C’est une start_routine.

    Sinon, comme il n’y a pas de synchronisme entre la création du thread enfant et l’exécution du thread parent, sauf au point de synchronisation join. Cette propriété est très importante parce qu’elle fait que :
    - soit la mémoire est libérée dans le thread enfant (méthode bousk, parfaitement correct)
    - soit la mémoire est libérée après le join (là aussi, parfaitement correct)
    - soit il faut définir un point de synchronisation entre les deux threads pour libérer dans le thread parent la mémoire à ce moment là (correct, mais compliqué à mettre en œuvre pour un bénéfice qui sera nul la plupart du temps).

    C’est ce qu’a dit fenkys, mais apparemment, il faut le répéter car ce n’est pas clair pour tout le monde.

    Comme on est en C avec des void*, il faut utiliser le seul outil disponible, à savoir la documentation, pour indiquer le mécanisme utilisé pour libérer les ressources (parce que ça ne concerne pas que la mémoire) passées dans le contexte d’appel.

  12. #12
    Expert confirmé
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Points : 4 388
    Points
    4 388
    Par défaut
    Whaou toutes les réponses

    Merci à vous.
    Citation Envoyé par Bousk Voir le message
    Salut,

    y'a pas de magie, et faut pas avoir peur de faire un simple cast.
    Btw ton paramètre tu le récupères en void*, donc tu dois de toutes façons le cast pour l'utiliser dans ta callback.
    Effectivement, ca me semble le plus simple, donc après le cast dans la callback, je peux le libérer avant la fin de la callback quand j'en es plus besoin.
    Je voulais savoir s'il n'y avait pas une meilleure méthode plus propre car j'avoue que je ne suis pas trop pour le cast...

    Bonne journée
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  13. #13
    Expert éminent sénior

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 045
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Bas Rhin (Alsace)

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

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 045
    Points : 11 368
    Points
    11 368
    Billets dans le blog
    10
    Par défaut
    Le principe est que start_routine doit être de la fome void *(*)(void *).
    Tu peux très bien déclarer ta start_routine de la forme void * MyRoutine( MaStruct * data );Ca déplace le cast au niveau du pointeur de fonction que tu donnes à pthread_create, mais au moins, au niveau de l'appel tu ne'as pas à le faire.
    Par contre, tu auras toujours un cast. Etant en C, je ne sais pas si tu peux t'en débarasser.
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

  14. #14
    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
    Il vaut mieux un cast dans la fonction elle-même qu'un cast de pointeur de fonction.
    En fait, beaucoup de choses valent mieux qu'un cast de pointeur de fonction.
    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.

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

Discussions similaires

  1. Libération de mémoire non réservée (operator=)
    Par 84mickael dans le forum C++
    Réponses: 7
    Dernier message: 27/05/2006, 14h30
  2. Problème libération de mémoire?
    Par Bartuk dans le forum C
    Réponses: 7
    Dernier message: 28/12/2005, 18h20
  3. Libération de mémoire
    Par petitcoucou31 dans le forum Langage
    Réponses: 1
    Dernier message: 16/09/2005, 15h10
  4. [Debutant(e)]problème de libération de mémoire
    Par skywalker3 dans le forum Eclipse Java
    Réponses: 1
    Dernier message: 10/02/2005, 18h38
  5. Réponses: 25
    Dernier message: 16/07/2003, 21h41

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