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 :

Empêcher : delete[] (wchar_t *)obj;


Sujet :

C++

  1. #1
    Membre expérimenté
    Inscrit en
    Octobre 2007
    Messages
    236
    Détails du profil
    Informations personnelles :
    Âge : 46

    Informations forums :
    Inscription : Octobre 2007
    Messages : 236
    Par défaut Empêcher : delete[] (wchar_t *)obj;
    Bonjour,
    J'ai une classe 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
     
    class foo
    {
    protected :
        wchar_t *buffer;
    public :
        operator wchar_t *()
        {
             return buffer;
        }
    };
    ...
    wchar_t *buf = (wchar_t *)fooobj;
    ...
    delete[] buf; //DANGER!
    J'ai changé en const mais ça n'a pas empêcher l'exécution de delete[].
    Je veux pas opter pour le retour d'un autre buffer car je vais oubliger les autres à faire un delete[] après chaque (wchar_t *)fooobj.

    Merci

  2. #2
    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
    Par défaut
    Bonjour,
    1/Solution documentaire : retourner un const en indiquant dans le contrat de ta classe que l'adresse retournée ne peut être deleté. Par exemple, std::string.c_str() te retourne un char* mais je te déconseille vivement de faire un delete dessus.
    2/Ne jamais renvoyer ton pointeur : les traitements devraient être dans foo ou une classe amie (donc de confiance) de foo.
    3/Utiliser un pointeur intelligent pour que personne ne soit tenté de faire des delete.

  3. #3
    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
    Mais un pointeur intelligent possède déjà le même problème: Il n'empêche pas de faire un delete sur les données qu'il pointe.

    Pour moi, la solution la plus évidente est la 1. La 2 est plus compliquée, mais peut-être meilleure à long-terme à moins qu'on ait besoin d'extensibilité.

    Edit: Ou peut-être retourner un itérateur?
    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.

  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
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Mais un pointeur intelligent possède déjà le même problème: Il n'empêche pas de faire un delete sur les données qu'il pointe.
    Effectivement. Mais d'une certaine façon tu n'as plus à faire à un pointeur mais à une valeur. Donc, tu n'es plus tenté par le delete.
    Citation Envoyé par Médinoc Voir le message
    Pour moi, la solution la plus évidente est la 1.
    Et pas forcément la plus choquante, d'autant s'il s'agit de pouvoir injecter la donnée dans une interface C par exemple et auquel cas la 2 ne pourrait s'appliquer.

    Citation Envoyé par Médinoc Voir le message
    La 2 est plus compliquée, mais peut-être meilleure à long-terme à moins qu'on ait besoin d'extensibilité.
    C'est clair. Elle permet surtout de masquer l'implémentation effective de buffer pour se concentrer sur le service de haut niveau proposé par foo.

  5. #5
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Et peut-être utiliser une fonction avec un nom explicite, plutôt qu'un opérateur de conversion, qui pourrait être appelé là où on ne veut pas.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  6. #6
    Membre expérimenté
    Inscrit en
    Octobre 2007
    Messages
    236
    Détails du profil
    Informations personnelles :
    Âge : 46

    Informations forums :
    Inscription : Octobre 2007
    Messages : 236
    Par défaut
    @ 3DArchi
    Merci pour l'article. Très intéressent. C'est mon premier projet C++ depuis des années. Je voulais éviter l'utilisation des templates et autres structures de données complexes mais bon. Je crois que j'ai pas le choix.

    @ JolyLoic
    Je crois que delete[] obj.GetBuffer(); causera les mêmes problèmes.

  7. #7
    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
    Mais paraîtra peut-être plus suspect.
    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.

  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
    Par défaut
    Citation Envoyé par emmr.rida Voir le message
    @ 3DArchi
    Merci pour l'article. Très intéressent. C'est mon premier projet C++ depuis des années. Je voulais éviter l'utilisation des templates et autres structures de données complexes mais bon. Je crois que j'ai pas le choix.
    Effectivement, et c'est même plutôt une bonne démarche que de s'intéresser à ces choses peut être un peu nouvelles pour toi mais indispensable pour réaliser du code C++ fiable.

    Citation Envoyé par emmr.rida Voir le message
    @ JolyLoic
    Je crois que delete[] obj.GetBuffer(); causera les mêmes problèmes.
    Pour ce cas particulier, je pense que tu te poses un faux problème. Si tu as besoin d'exposer ton buffer, alors exposte le (en constant) et à charge de l'utilisateur de ta classe de ne pas faire de delete. C'est le contrat (de confiance) qui lie ta classe et ses clients. C'est une erreur d'être (trop) défensif par rapport à ce contrat.

  9. #9
    Membre expérimenté
    Inscrit en
    Octobre 2007
    Messages
    236
    Détails du profil
    Informations personnelles :
    Âge : 46

    Informations forums :
    Inscription : Octobre 2007
    Messages : 236
    Par défaut
    Exposer mon buffer pour des raisons d'utilisation de la bibliothèque standard pour affichage ou autre. L'autre altérnative qui est d'exposer une copie du buffer risque de générer des fuites de mémoire ainsi qu'une perte de performances surtout pour une classe qui est instanciée massivement durant l'exécution du programme.

  10. #10
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par emmr.rida Voir le message
    @ JolyLoic
    Je crois que delete[] obj.GetBuffer(); causera les mêmes problèmes.
    Oui, mais quelqu'un qui ferait delete[] obj.internalBuffer() ne serait pas simplement étourdi, mais mal intentionné...
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  11. #11
    Membre expérimenté
    Inscrit en
    Octobre 2007
    Messages
    236
    Détails du profil
    Informations personnelles :
    Âge : 46

    Informations forums :
    Inscription : Octobre 2007
    Messages : 236
    Par défaut
    Oui c'est vrai, mais je préfére comme même ne pas prendre le risque de tomber dans ce cas et l'autre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    wchar_t *buffer = obj.GetBuffer();
    ...
    delete[] buffer;

  12. #12
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Si tu veux empêcher delete, n'expose pas le pointeur. Si tu exposes le pointeur, tu ne peux pas empêcher d'appliquer delete dessus.

    Suivant la raison pour laquelle tu veux exposer le pointeur, tu peux encapsuler le résultat, mais si c'est pour des raisons de compatibilité avec des interfaces ayant besoin d'un pointeur, rien n'empêche ces fonctions de faire un delete quelque part.

  13. #13
    Membre expérimenté
    Inscrit en
    Octobre 2007
    Messages
    236
    Détails du profil
    Informations personnelles :
    Âge : 46

    Informations forums :
    Inscription : Octobre 2007
    Messages : 236
    Par défaut
    Oui, je voie.
    Merci pour vos réponses.

  14. #14
    Membre Expert
    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
    Par défaut
    Est-ce que ça ne serait pas le cas typique d'utilisation d'un boost::weak_ptr ?

  15. #15
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Est-ce que ça ne serait pas le cas typique d'utilisation d'un boost::weak_ptr ?
    N'ayant aucune idée de pourquoi il faut obtenir un pointeur, j'ai du mal à voir s'il s'agit d'un cas où l'utilisation d'un weak_ptr est possible, sans parler de typique.

    weak_ptr sert normalement quand on a des shared_ptr (donc quand la responsabilité de la durée de vie d'un objet est partagée, si on a des shared_ptr sans qu'il y ait partage de cette durée de vie, on est déjà dans de l'atypique) et qu'il faut conserver des pointeurs qui ne partagent pas la responsabilité de la durée de vie sans qu'on puisse être sûr que l'objet sera bien toujours valide.

  16. #16
    Membre éclairé Avatar de cynique
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    60
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 60
    Par défaut
    Citation Envoyé par emmr.rida Voir le message
    Bonjour,
    J'ai une classe 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
     
    class foo
    {
    protected :
        wchar_t *buffer;
    public :
        operator wchar_t *()
        {
             return buffer;
        }
    };
    ...
    wchar_t *buf = (wchar_t *)fooobj;
    ...
    delete[] buf; //DANGER!
    J'ai changé en const mais ça n'a pas empêcher l'exécution de delete[].
    Je veux pas opter pour le retour d'un autre buffer car je vais oubliger les autres à faire un delete[] après chaque (wchar_t *)fooobj.

    Merci
    Personne ne l'a fait, donc il faut que je te demande: Pourquoi est-ce que tu veux exposer le buffer?

    C'est un tableau, alloué avec new [], et pour moi, ça dit que tu as besoin d'un "wchar_t operator [](int)" ou peut-être "wchar_t operator[](size_t)". Puis l'utilisateur peut faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
      foo bar;
     
      // ...
     
      wchar_t ch = bar[1];
    Si tu écris "wchar_t &operator [](size_t)", on peut faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
      foo bar;
     
      // ...
     
      bar[2] = 'H';
    Mais aussi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
      foo bar;
     
      // ...
     
      delete[] &foo[0];
    Pour éviter ça:
    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
     
      class foo
      {
        wchar_t *buffer;
      public:
        // ...
        class foo_gate
        {
          wchar_t &m_ch;
        public:
          foo_gate( wchar_t &the_char ) : m_ch(the_char) {}
          foo_gate &operator =( wchar_t new_char ) { m_ch = new_char; }
     
          operator wchar_t() { return m_ch; }
        };
     
        foo_gate operator[]( size_t index )
        {
          return foo_gate( buffer[index] );
        }
      };
     
      foo bar;
     
      // ...
     
      ch = bar[3];  // Note 1
     
      bar[4] = ch;  // Note 2
     
      wchar_t *p = &bar[0];  // Note 3
    Note 1: ch = bar.operator[](3).operator wchar_t();

    Note 2: bar.operator[](4).operator =(ch);

    Note 3: Cette ligne ne compile pas parce que "&bar[0]" est un "foo::foo_gate *".

    C'est possible que la performance soit un peu pire, mais un bon compilateur fixera ça.

    Bonne Chance!

  17. #17
    Membre expérimenté
    Inscrit en
    Octobre 2007
    Messages
    236
    Détails du profil
    Informations personnelles :
    Âge : 46

    Informations forums :
    Inscription : Octobre 2007
    Messages : 236
    Par défaut
    J'ai besoin d'exposer le buffer pour des raisons d'affichages sur console à l'aides des fonctions de la bibliothèque standard et ça le temps de développer mes propres routines d'affichage prenant l'objet de la classe exposant le buffer (pour le moment!) comme paramètre et non pas le buffer interne lui même.
    Concernant ta solution, je dois exposer le buffer tout entier et non pas les éléments wchar_t.

    Merci.

  18. #18
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Mmm, tu veux pouvoir faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    cout << maClasse << endl;
    Si c'est bien ça, c'est tout simple à écrire, et ça t'évitera des soucis.

    http://cpp.developpez.com/faq/cpp/?p...teur_affichage

    Sinon, tu pourrais préciser ?
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  19. #19
    Membre expérimenté
    Inscrit en
    Octobre 2007
    Messages
    236
    Détails du profil
    Informations personnelles :
    Âge : 46

    Informations forums :
    Inscription : Octobre 2007
    Messages : 236
    Par défaut
    Merci JolyLoic, l'article est très intéressant.

    Ce que je peux comprendre à partir de cette discussion, c'est qu'il faut préviligier code fiable au lieu d'un code s'exécutant très vite exposant des pointeur vers des données internes d'une classe. Exemple :
    Pour une classe qui gère une chaine de caractères, au lieux d'utiliser le constructeur acceptant un pointeur vers une chaine de caractères pour copier les objets du même type...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    classe foo
    {
        foo(wchar_t *str)
        {
            buffer = new wchar_t[wcslen(str)];
            wcscpy(buffer, str);
            ...
        }
        ...
        operator wchar_t *();
    };
    Utiliser un code un petit peu long mais fiable...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    class foo
    {
        foo(foo &f)
        {
             buffer = new wchar_t[foo.GetLength()];
             for(int i = 0; i < foo.GetLength(); i++) buffer[i] = foo[i];
             ...
        }
        ...
        wchar_t operator[](int index);
    }
    Merci les gars

  20. #20
    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
    Ils manquent cruellement de const, tes deux derniers codes...
    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.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 7
    Dernier message: 23/07/2013, 12h42
  2. Empêcher le delete dans un trigger
    Par Phreak0x dans le forum MySQL
    Réponses: 4
    Dernier message: 06/12/2008, 22h09
  3. Réponses: 2
    Dernier message: 21/05/2008, 10h01
  4. [langage] delete de fichier
    Par lolive dans le forum Langage
    Réponses: 2
    Dernier message: 24/04/2003, 15h04
  5. [MSXML] Comment empécher la conversion des entités ?
    Par nima dans le forum XSL/XSLT/XPATH
    Réponses: 3
    Dernier message: 08/11/2002, 14h14

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