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 :

Transtypage sur itérateur


Sujet :

C++

  1. #1
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut Transtypage sur itérateur
    Hello,

    Soit une classe Pouet, et la liste STL suivante, accompagnée de son itérateur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    list<Pouet*> dudule;
    list<Pouet*>::iterator iter;
    La mémoire pour les Pouet de la liste a été allouée avec des new.

    Quelle est la meilleure méthode pour désallouer la mémoire ?

    Pour l'instant, j'utilise une boucle qui fait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    for (iter = pouetList.begin(); iter != pouet.end(); ++iter)
    {
        Pouet* dudule = (Pouet*)*iter;
        delete dudule ;
    }
    Mais d'une part, le transtypage étant à la C, j'aimeras le transformer en static_cast ou en dynamic_cast. Mais lequel utiliser ?
    D'ailleurs, un transtypage est-il nécessaire ?

    Sinon, ne devrais-je tout simplement pas utiliser des auto_ptr pour mes Pouet ?
    J'ai découvert ça il n'y a pas très longtemps, et je ne sais pas toujours dans quels cas il faut l'utiliser.

    Merci.

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    92
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Mai 2005
    Messages : 92
    Par défaut
    Le transtypage n'est pas nécessaire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for (iter = pouet.begin(); iter != pouet.end(); ++iter)
    {
        delete *iter;
    }
    suffit (le type est inscrit dans le paramètre template de list).

    Pour les auto_ptr, attention : cf. FAQ.

    Sinon, les smart pointers de Boost (utilise shared_ptr) fonctionnent très bien. Il existe aussi des conteneurs de pointeurs dans Boost, calqués sur la STL, mais je n'ai jamais testé.

  3. #3
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Merci.

    J'avais oublié que je ne pouvais utiliser auto_ptr avec la STL.

  4. #4
    Membre émérite
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Par défaut
    He ouais, c'est un peu stupide mais c'est ainsi.
    Sinon, il faut déja te demander pourquoi tu stockes des pointeurs et pas des instances seules. Le cas le plus classique (et le moins contestable) serait celui où tu fais du polymorphisme objet. Dans d'autre cas, il sera généralement possible de se passer des pointeurs.
    Si tu n'as vraiment pas le choix, tu peux effectivement utiliser des shared_ptr, solution à laquelle je préfèrerais l'utilisation de ptr_container. Si tu n'as pas boost sous la main, un vector<*> est la seule solution mais uniquement si tu le place dans une classe/structure bien protégée, même si ce n'est dédié qu'à ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct vector_pouet {
       vector<pouet*> vec;
       ~vector_pouet () {...}
    }
    Ne va pas instancier directement un vector<*> comme variable locale, au sinon le mauvais code pas exception-safe te guete...

  5. #5
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Je fais effectivement du polymorphisme.

    Je ne comprend pas bien l'astuce de la structure, du vector, etc... ??

  6. #6
    Membre émérite
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Par défaut
    Tu as déja entendu parler du RAII? Non? Et bien en gros, si tu as un code qui ressemble à ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    machin* x = new machin();
    ...
    delete x;
    ce n'est pas safe.
    Pourquoi? Tout simplement parceque les trois petits points sont susceptibles de lancer une exception, et dans ce cas le delete ne sera pas effectué. Si tu es en train de te dire que tu n'as qu'à faire attention à pas utiliser de fonctions lançant des exceptions c'est débile, tu ne connais pas toutes les fonctions et il est beaucoup plus simple de considérer que chaque ligne de C++ est susceptible d'en lancer. Il suffit alors d'employer un beau barème bien systématique pour que tout soit exception-safe.
    Voila pourquoi on recommande l'utilisation de smart pointers à tout va, et pourquoi je te déconseille d'instancier directement un vector<*> sur la pile. Rien qu'en encapsulant ton tableau dans une structure avec un destructeur correct tu n'auras aucun problème:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void do_something() {
    vector_pouet x;
    ...
    //appel implicite du destructeur de vector_pouet, et donc destruction
    //des objets pointés même si une exception est lancée
    }

  7. #7
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    92
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Mai 2005
    Messages : 92
    Par défaut
    Citation Envoyé par zais_ethael Voir le message
    utiliser des shared_ptr, solution à laquelle je préfèrerais l'utilisation de ptr_container
    Ça m'a donné l'occasion de relire un peu la doc sur ptr_container, et c'est vrai que ça a l'air plus pertinent que shared_ptr quand on ne cherche qu'à stocker des pointeurs vers des classes polymorphiques. Je vais potasser.

  8. #8
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Les ptr_container sont excellents pour avoir déjà utilisé ptr_vector et ptr_map...

    Bonne continuation !

  9. #9
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Citation Envoyé par zais_ethael Voir le message
    Tu as déja entendu parler du RAII? Non? Et bien en gros, si tu as un code qui ressemble à ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    machin* x = new machin();
    ...
    delete x;
    ce n'est pas safe.
    En l'occurrence, ma liste STL est une donnée membre d'une classe A, et je la remplis de pointeurs dans une fonction membre.

    Je libère les pointeurs alloués dans le destructeur de la classe A.

    Cela est-il suffisament safe ?

  10. #10
    Membre émérite
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Par défaut
    Oui, tout à fait.
    Néanmoins, si tu devais déclarer plusieurs fois ce type de tableau, ce serait quand même mieux de chercher une solution plus réutilisable.
    PS: faire très très attention aux copies. Normalement, un objet polymorphe n'est jamais copiable, donc toute classe qui gère le cycle de vie d'un de ces objets devrait toujours être déclarée non copiable. Pour rappel:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class machin {
    ...
    private:
    machin(const machin&);
    machin& operator=(const machin&);
    ...
    }

  11. #11
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Citation Envoyé par zais_ethael Voir le message
    PS: faire très très attention aux copies. Normalement, un objet polymorphe n'est jamais copiable, donc toute classe qui gère le cycle de vie d'un de ces objets devrait toujours être déclarée non copiable.
    pourquoi??

  12. #12
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    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 395
    Par défaut
    Parce qu'on pourrait "copier" un objet d'une classe fille en objet de la classe mère, ce qui signifie généralement des problèmes.

    La plupart des objets polymorphes "copiables" sont en fait "clonables": Ils ont une fonction membre virtuelle clone() et leur constructeur de copie est private ou protected...
    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.

  13. #13
    Membre émérite
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Par défaut
    Avec une classe A et une classe B qui en hérite:
    Construction d'un objet à partir d'un objet polymorphe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    A* x = ...;
    A* y = ??(x);
    Question: comment on détermine la classe à construire??

    Utilisation de l'opérateur = :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    A* x = ...;
    A* y = ...;
    (*y) = (*x);
    Tu crois vraiment que ça peut fonctionner? Les classes A et B n'occupent pas le même espace mémoire, et l'opérateur = ne peut pas modifier l'espace alloué.

    Conclusion => un objet polymorphe ne peut être copié (il peut éventuellement être cloné, mais la c'est à toi de faire ta propre hiérarchie de classes clonables).

    Si une classe gère le cycle de vie d'une donnée pointée, elle doit dupliquer ces données lors de la copie c'est logique (comme tous les conteneurs de la stl le font), mais si ce n'est pas possible il faut interdire la copie. Eventuellement, on peut mettre en place des modes de fonctionnement plus exotiques, comme celui d'auto_ptr, mais ce ne serait pas très user-friendly, la personne qui utiliserait la classe devrait faire attention aux copies pour ne pas se retrouver avec des données incohérentes.

    Tu commences à comprendre pourquoi certains (tels que moi) disent que le C++ n'est pas un langage orienté objet?

  14. #14
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Parce qu'on pourrait "copier" un objet d'une classe fille en objet de la classe mère, ce qui signifie généralement des problèmes.

    La plupart des objets polymorphes "copiables" sont en fait "clonables": Ils ont une fonction membre virtuelle clone() et leur constructeur de copie est private ou protected...
    Ok, merci. Je pensais qu'il pouvait y avoir une autre raison

    Citation Envoyé par zais_ethael Voir le message
    Si une classe gère le cycle de vie d'une donnée pointée, elle doit dupliquer ces données lors de la copie c'est logique (comme tous les conteneurs de la stl le font), mais si ce n'est pas possible il faut interdire la copie. Eventuellement, on peut mettre en place des modes de fonctionnement plus exotiques, comme celui d'auto_ptr, mais ce ne serait pas très user-friendly, la personne qui utiliserait la classe devrait faire attention aux copies pour ne pas se retrouver avec des données incohérentes.

    Tu commences à comprendre pourquoi certains (tels que moi) disent que le C++ n'est pas un langage orienté objet?
    ouawow.. pas du tout

Discussions similaires

  1. Aide sur les itérateurs
    Par Baquardie dans le forum C#
    Réponses: 1
    Dernier message: 23/04/2008, 22h04
  2. transtypage (cast) sur hashtable
    Par ashash dans le forum Langage
    Réponses: 5
    Dernier message: 30/11/2007, 14h07
  3. Transtypage Pointeur sur Fonction
    Par oupslelapin dans le forum C++
    Réponses: 2
    Dernier message: 30/05/2007, 11h54
  4. débutant : question technique sur transtypage
    Par flamant dans le forum C++
    Réponses: 9
    Dernier message: 22/01/2007, 11h32
  5. Transtypages sur des pointeurs de fonction
    Par gege2061 dans le forum GTK+ avec C & C++
    Réponses: 5
    Dernier message: 05/01/2007, 15h01

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