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 :

Différencier les pointeurs de variable dynamique des autre pointeurs


Sujet :

C++

  1. #1
    Membre averti Avatar de Ekinoks
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2003
    Messages
    687
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2003
    Messages : 687
    Points : 358
    Points
    358
    Par défaut Différencier les pointeurs de variable dynamique des autre pointeurs
    Salut !

    J'essaye de trouver un moyen de différencier un pointeur vers une variable allouer dynamiquement des autre pointeurs, pour pouvoir effectuer un delete si il a était créé dynamiquement, et ne rien faire si il n'a pas était créé dynamiquement.

    La mémoire d'un programme C semble être gérer de cette manière :
    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
     
    ________________
    |                |
    | VARIABLE LOCAL |
    |      (pile)    |
    |________________|
    |       | |      |
    |        V       |
    |                |
    |      FREE      |
    |                |
    |       ^        |
    |______| |_______|
    |                |
    | ALLOCATION     |
    |      (tas)     |
    |________________|
    |                |
    | VARIABLE STATIC|
    | (segment data) |
    |________________|
    |                |
    | VARIABLE GLOBAL|
    |  (segment bss) |
    |________________|
    |                |
    | FONCTION       |
    | (segment text) |
    |________________|
    Une solution consisterais donc à vérifier que la valeur du pointeur soit compris entre le pointeur la dernière variable static et le pointeur la dernière variable local.


    Pour récupérer la dernière valeur de la variable local, c'est pas bien compliquer.
    Par contre, pour arriver à récupérer la valeur de la dernière variable static (ou la première variable dynamique) c'est plus compliqué (surtout si on a plusieurs fichier sources).

    Avez-vous une idée de comment faire ?

    Ou peu être une autre méthode plus simple ?

    Merci pour votre aide.

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 379
    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 379
    Points : 41 573
    Points
    41 573
    Par défaut
    Cela n'est absolument pas fiable.
    La seule chose que tu peux faire, c'est remplacer les pointeurs "bètes" par des pointeurs intelligents qui mémorisent le truc (possible facilement en C++, mais impossible de faire un truc vraiment pratique en C).

    Pour les objets alloués sur le tas, tu peux même ajouter un comptage de références (qui peut même être un comptage intrusif si tu aménages exprès l'allocateur).

  3. #3
    Membre confirmé
    Avatar de NewbiZ
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2002
    Messages
    184
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2002
    Messages : 184
    Points : 563
    Points
    563
    Par défaut
    Ca a déjà été abordé maintes et maintes fois sur comp.lang.c++, et effectivement la seule solution potable est celle que tu cites. Le seul défaut serait que c'est intrinsèquement sujet à nombre de problèmes de portabilité.

    Comme dit par Médinoc, pourquoi vouloir éloigner autant la logique de destruction des variables? Les smart pointers résolvent bien ce problème.

    Le plus propre serait encore de se pencher sur les différentes bibliothèques de reflection pour C++, qui se proposent d'ajouter tout un tas de métapropriétés aux variables.

  4. #4
    Membre confirmé Avatar de themadmax
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    446
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 446
    Points : 496
    Points
    496
    Par défaut
    Le plus propre serait encore de se pencher sur les différentes bibliothèques de reflection pour C++, qui se proposent d'ajouter tout un tas de métapropriétés aux variables.
    Je serai bien intéressé par ce type de bib. si tu avais des noms...
    Merci

  5. #5
    Membre averti Avatar de Ekinoks
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2003
    Messages
    687
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2003
    Messages : 687
    Points : 358
    Points
    358
    Par défaut
    Merci pour vos réponses


    Désolé de répondre plusieurs jour après vos réponses, mais c'est que je voulais bien étudier les solutions que vous m'avez proposé avant ^^;

    Donc, j'ai réfléchie pour me créer des pointeurs intelligents et ca résous effectivement un bon nombre de petit désagrément comme empêcher de déallouer un objet déjà déallouer...

    Par contre le problème de la différenciation entre les pointeurs de variable dynamique des autre pointeurs persiste toujours.

    Voici un petit exemple en utilisant mon nouveau pointeur intelligent ^^
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    int main()
    {
       Ptr<Object> p;
       p = new Object(); 
       p.destroy();           // l'objet est déalouer sans poser de problème.
     
       Object o;
       p = &o;
       p.destroy();   // AIE !! Erreur ! :'(
     
       return 0;
    }

    A la limite une solution serais d'obliger de créer des instance d'Object avec new comme ca :
    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
     
    class Object
    {
       Object(){}
       public :
          static Object* new_Object(){*return new Object(); }
    }
     
    int main()
    {
       Ptr<Object> p;
       p = Object::new_Object(); 
       p.destroy();           // l'objet est déalouer sans poser de problème.
     
       Object o;   // cool, ca bloque à la compilation ! =)
       p = &o;
       p.destroy();
     
       return 0;
    }
    Le problème est que le code devient plus lourd et moins intuitif non ?

    Donc pour résumer, pour empécher que l'erreur de mon premier exemple est lieu il y a deux solution :
    1> A l'execution : Le pointeur intelligent arrive à faire la différence entre un pointeur "délétable" et un pointeur non "délétable"
    2> A la compilation : On génère une erreur à la compilation si on donne un pointeur non "délétable" au pointeur intelligent (ce que j'essaye de faire indirectement en obligent d'utiliser "new")


    Pour la solution numéro (1), je ne vois pas comment faire (si ce n'est en comparent valeur du pointeur pour arriver à déterminer dans quel segment il se trouve mais comme vous l'avez souligné c'est pas portable et pas fiable)
    Pour la solution numéro (2), il y a bien la solution que je propose dans mon second exemple, mais elle ne me semble pas très propre et pas suffisamment intuitif à utiliser.


    Savez vous comment implémenter proprement la solution 1 ou 2 ? ou peu être avez vous d'autre idée ?

    Merci pour votre aide.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 627
    Points : 30 692
    Points
    30 692
    Par défaut
    Salut,

    L'idéal est quand même toujours de partager les responsabilités.

    Ainsi, de prime abord, je vois principalement deux raisons d'utiliser des pointeurs:

    La première, c'est de fournir une référence à un objet qui se trouve ailleurs, et la seconde est de permettre un mécanisme de polymorphisme.

    Dans le premier cas, tu peux très bien avoir un conteneur "séparé" d'objets non alloués de manière dynamiques auquel font référence tous les pointeurs.

    Lors de l'utilisation du pointeur, tu n'a alors qu'à t'inquiéter d'utiliser le pointeur, mais c'est le conteneur qui doit décider d'en créer de nouveaux ou d'en supprimer. (il faut, bien sûr, prévoir d'indiquer aux éléments externes qui utilisent les pointeurs quand ils deviennent invalide du fait de la destruction de l'objet sur lequel ils pointent).
    Cela pourrait prendre une forme proche de
    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
    class Mediator;
    class Controlee;
    class Object
    {
        /* le type d'objet que tu veux utiliser */
    };
    class Conteneur // éventuellement sous la forme d'un singleton ou 
                    // contenu dans un élément plus global ;)
    {
        public:
            Conteneur(Mediator* media):media(media),tab()
            createObject(/*parametre nécessaires à la création d'un objet*/)
            {
                tab.push_back(Object(/*paramètres*/));
            }
            Objet* operator[](size_t ind)
            {
                 return &tab[ind];
            }
            removeObject(size_t ind)
            {
                 media->remove(&tab[ind]);
                 tab.erase(ind);
            }
        private:
            Mediator * media;
            std::vector<Object> tab;
    };
    class Mediator // sans doute aussi un singleton, ou contenu dans une 
                   // structure plus globale
    {
        public:
            Mediator():tab(){}
            ~Mediator(){}
            Controlee& operator[](size_t ind)
            {
                return tab[ind];
            }
            void addControlee(Object * ptr)
            {
                tab.push_back(Controlee(ptr));
            }
            void remove(Object* ptr)
            {
                tab.erase(tab.removeif(tab.begin(), tab.end(),Controlee.equal(ptr)),
                              tab.end());
            }
        private:
            std::vector<Controlee> tab;
    };
    class Controlee
    {
        public:
            Controlee(Object* ptr):ptr(ptr){}
            ~Controlee(){}
            friend class equal;
            class equal
            {
                 bool operator()(const Controlee& c1, const Controlee& c2)
                 {
                     return c1.ptr==c2.ptr;
                 }
            }
        private:
            Object* ptr;
    };
    (il reste sans doute une ou l'autre erreur... mais je n'ai pas encore dormi )

    Dans le deuxième cas, cela passera par une allocation dynamique de la mémoire, et, fatalement, par une libération de cette mémoire lorsque l'objet doit être détruit.

    Mais, quoi qu'il en soit, ce sera toujours au conteneur de décider de l'allocation et de la libération des pointeurs

    En tout état de cause, si tu en viens à vouloir mélanger les pointeurs statiques et les pointeurs dynamiques dans un même conteneur, tu peux réellement te dire qu'il y a sans doute comme un problème de conception quelque part

  7. #7
    Membre confirmé
    Avatar de NewbiZ
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2002
    Messages
    184
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2002
    Messages : 184
    Points : 563
    Points
    563
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
      Ptr<Object> p;
      p = new Object(); 
      p.destroy();           // l'objet est déalouer sans poser de problème.
     
      Object o;
      p = &o;
      p.destroy();   // AIE !! Erreur ! :'(
    Les pointeurs intelligents sont fait pour une sémantique de ... pointeurs. Ce que tu décris là est une erreur qui pourrait aussi bien arriver avec des pointeurs classiques
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
      Object* p;
      Object  o;
      p = &o;
      delete p;
    Bref, tu ne peux pas trouver de palliatif à des erreurs sémantiques. Et vouloir manager un objet en mémoire statique avec un manageur d'objets en mémoire dynamique est de facto une erreur sémantique.

  8. #8
    Membre averti Avatar de Ekinoks
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2003
    Messages
    687
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2003
    Messages : 687
    Points : 358
    Points
    358
    Par défaut
    Merci pour vos réponses.

    Citation Envoyé par NewbiZ Voir le message
    [CODE]Bref, tu ne peux pas trouver de palliatif à des erreurs sémantiques. Et vouloir manager un objet en mémoire statique avec un manageur d'objets en mémoire dynamique est de facto une erreur sémantique.
    Ha, d'accord , c'était exactement ça que je voulait faire :^X
    j'ai un objet qui récupère un pointeur d'un autre objet, et c'est a lui de faire le delete, je cherchais un moyen d'empêcher de faire cette erreur de sémantiques...

    Ok, donc si j'ai bien compris, ca sera au personne qui utiliserons mes sources de faire attention de ne pas faire cette erreur de sémantiques et non pas à mon compilateur de vérifier ?

    koala01> Ok, par contre, je crins n'avoir pas tout compris à ton code source :'(
    Déjà pour quoi utiliser 3 class (Conteneur, Mediator, Controlee) ?
    Et aussi pour quoi es que tu utilise la class "equal" en définissant l'opérateur "()" ? et pas simplement créer une méthode "equal" ?

    Merci.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 627
    Points : 30 692
    Points
    30 692
    Par défaut
    Je vais reprendre mon raisonnement depuis de début, cela te permettra de mieux comprendre.

    Déjà, il est important de garder en tête le fait que, idéalement, il faut déléguer au maximum les responsabilités: bien souvent, il apparait que, si un type donné a plus d'une responsabilité, c'est sans doute qu'il en a trop.

    Bien sûr, tu finira toujours par arriver à un moment donné où un type doné sera responsable de plusieurs choses en même temps, mais le problème ne se pose pas vraiment ici

    De plus, quand tu dois faire cohabiter plusieurs instances d'un même objet dans du code, tu crées ce que l'on appelle de manière tout à fait générale une "collection d'objet".

    Que tu le fasse d'une manière "C style" ou que tu utilise les conteneurs fournis par le standard ne change finalement pas grand chose.

    Tant que cette collection d'objet est "à usage interne" (comprend: tant que cette collection n'est pas destinée à devoir communiquer avec autre chose que les variables déclarées dans la fonction ou les membres de la classe dans laquelle elle se trouve), tu peux très bien te contenter de gérer cette collection de manière tout à fait classique, sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void fonction()
    {
        /* la manière C style */
        Objet * tab;
        tab = new Objet[nombre];
        /* et avant de sortir de la fonction, ne pas oublier le*/
        delete tab;
        /* ou à la manière "C++" */
        std::vector<Objet> tab;
    }
    Cependant, on se rend souvent compte qu'il est intéressant de créer un type qui est définitivement "la collection d'objets", et qui aura pour principale responsabilité de gérer l'existence des différentes instances du type concerné.

    Ne serait-ce que parce qu'il est souvent intéressant de pouvoir passer la collection d'objet entière comme paramètre d'une fonction, ou parce que cette collection doit être en mesure de communiquer avec autre chose

    La classe Conteneur donne un aperçu de ce nouveau type qui est une "collection d'Objet"

    Selon tes explications, il existe un type qui utilise un pointeur vers une instance de type Object. C'est la classe que j'ai nommée Observee dans le code.

    Or, on se doute que - quelque part dans le code - il sera nécessaire de gérer plusieurs instances de ce type particulier (Observee) en même temps.

    Une même cause ayant les mêmes effets, il semble donc tout à fait cohérent de créer un type particulier de "collection d'Observee" qui se chargera de leur gestion.

    Seulement, voilà... Le type Observee n'a - a priori - aucune raison d'être responsable de la création ou de la destruction des instances du type Object... cette responsabilité est d'ailleurs déjà prise en charge par ... la "collection d'Object" (que j'ai nommée Conteneur dans le code).

    Mais cela va nous poser un problème de taille: Comme les objets de type Observee utilisent un pointeurs vers un objet de type Object, nous courrons le risque de voir ce pointeur... devenir invalide... avec tous les problèmes que cela peut impliquer.

    Il faut donc prévoir un mécanisme qui s'assurera qu'il ne reste aucune instance du type Observee dont le pointeur (nommé ptr dans le code) est devenu invalide.

    La responsabilité de ce mécanisme échoit, en toute logique, à la "collection d'Observee". C'est le role joué par la méthode remove de la classe Mediator.

    En outre, nous nous rendons compte du fait que, chaque fois que nous supprimerons un élément de la "collection d'Object", nous courrons le risque de voir un ou plusieurs objet(s) de type Observee devenir invalide(s).

    Si donc nous pouvons prévoir un moyen ( qui n'est pas représenté dans le code que j'ai présenté) de supprimer un élément de la "collection d'Observee" de manière indépendante, nous devons nous assurer du fait que, chaque fois qu'un élément de "la collection d'Object" est supprimé, une vérification et une suppression des éléments Observee qui référencent l'élément Object supprimé soient effectuées.

    Cela implique donc que la "collection d'Object" transmette systématiquement toute suppression d'un de ses éléments à la "collection d'Observee", et que cette transmission provoque la suppression des éléments Observee devenus invalides.

    C'est la raison pour laquelle la classe "Conteneur" (qui est la "collection d'Object") dispose d'un pointeurs sur la classe "Mediator", mais aussi la raison pour laquelle, la méthode removeObject commence par appeler la méthode media->remove avant de supprimer réellement l'élément de type Object

    Enfin, si j'ai créé une classe imbriquée equal pour laquelle j'ai défini l'operateur () ( je viens de me rendre compte que l'opérateur devait être déclaré avec une accessibilité publique), c'est pour que cette classe particulière puisse me servir de prédicat.

    En effet, si j'avais simplement défini une méthode "equal" dans la classe Observee, la méthode aurait été dépendante d'une instance particulière du type Observee, et je n'aurais pas pu l'utiliser avec les méthodes fournies par les différents conteneurs standards

  10. #10
    Membre averti Avatar de Ekinoks
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2003
    Messages
    687
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2003
    Messages : 687
    Points : 358
    Points
    358
    Par défaut
    Tout d'abord koala01, un grand MERCI pour temps que tu as consacré à écrire ce jolie poste

    Je vois que j'ai encore beaucoup de chose à apprendre... ^^;


    Après plusieurs relectures et plusieurs petits schémas, j'ai fini par comprendre ! (enfin j'espère )

    J'écris ce que j'ai compris, dit moi si j'ai tout compris de travers ^^


    En fait l'astuce consiste à obliger de passer par un objet "Conteneur" pour pouvoir créer des objets "Object", de cette manier c'est "Conteneur" qui s'occupe de créer, stoker puis supprimer les objet "Object".

    Pour pouvoir utiliser les "Object" créé par "Conteneur", on utilise "Observee" (qui est en fait une sorte de pointeur intelligent vue qu'il s'occupe de gérer le pointeur ?)

    Pour terminer, pour que les objet "Observee" soit en adéquation avec les objet réel stoker dans "Conteneur", on utilise "Mediator".


    C'est bon j'ai juste ?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 627
    Points : 30 692
    Points
    30 692
    Par défaut
    Dans les grandes lignes, c'est bien l'idée générale...

    A ceci près que la classe Observee n'a vraiment rien d'un pointeur intelligent: ce n'est vraiment qu'un type qui... utilise des comportement fournis par la classe Object.

    C'est plutôt l'amélioration d'une relation proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
      N <---> N
    objet   objet
      de     de
    type 1  type 2
    , en intercalant au milieu une (ou plusieurs) classes en vue d'avoir des arités unique dans la relation qui devient de l'ordre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
      N   <-------->  1 <--------> 1 <--------> N
    Objet de     conteneur     conteneur      objet 
    type 1       d'objet de    d'objets     de type 2
                  type 1       de type 2
    le tout en s'assurant que chaque type particulier n'aura que la responsabilité qui lui échoit

  12. #12
    Membre averti Avatar de Ekinoks
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2003
    Messages
    687
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2003
    Messages : 687
    Points : 358
    Points
    358
    Par défaut
    Ok cool, j'ai effectivement compris !

    Je pense que je peu mettre le sujet en résolue...


    Merci à tout le monde pour vos participation !

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 16/07/2013, 17h57
  2. Réponses: 2
    Dernier message: 23/09/2009, 15h40
  3. Ajout d'une variable dynamique de type pointeur
    Par mmooaa dans le forum Langage
    Réponses: 3
    Dernier message: 02/01/2007, 23h04
  4. Réponses: 2
    Dernier message: 19/07/2006, 00h12
  5. Réponses: 16
    Dernier message: 27/05/2006, 08h40

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