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

Langage C++ Discussion :

Tableau d'objets et scope


Sujet :

Langage C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Février 2005
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 52
    Points : 47
    Points
    47
    Par défaut Tableau d'objets et scope
    Salut,

    Je me mets à programmer en C sur un microcontroleur. Je fais plutôt du java d'habitude mais je voudrais communiquer avec une carte arduino.

    Je voudrais manipuler un ensemble d'objets variable et les faire bosser dans une boucle.

    Voici le code que j'utilise

    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
    class Animal
    {
      protected :
      int _num ;
     
      public :
      Animal(){}
      Animal( int num )
      {
        _num = num ;
      }
     
      virtual void parle() const=0 ;
    };
     
    class Chien :
    public Animal
    {
      public :
     
      Chien( int num ):
      Animal( num )
      {
      }
     
      virtual void parle() const
      {
        Serial.println("wouarf");
      }
    };
     
    class Chat :
    public Animal
    {
      public :
     
      Chat( int num ):
      Animal( num )
      {
      }
     
      virtual void parle() const
      {
        Serial.println("miaou");
      }
    };
     
    Animal * poly[20];
     
    int nbBetes = 0 ;
     
    Chien c1 = Chien(1);
    //Chat c2 = Chat(2);
     
    void setup()
    {
      Serial.begin(9600);
     
      //Chat c2 = Chat(2);
     
      poly[nbBetes++] = &c1;
      poly[nbBetes++] = (Chat*)malloc( sizeof( Chat ) );
    }
     
    void loop()
    {
      Serial.println( millis() );
      for( int i = 0 ; i < nbBetes ; i++ )
      {
        poly[i]->parle();
        delay( 1000 );
      }  
    }
    Je n'ai pas droit au mot clef "new". La fonction setup() est exécutée en premier, loop() tourne en boucle.

    En fait je cherche à remplir le tableau poly avec des objets. L'objet Chien est déclaré en dur et en global et ça fonctionne. Si j'essaye de créer le Chat à l'intérieur de la fonction setup() ça plante et le microcontrôleur reboot. On me dit que c'est un problème de scope, mais existe-t'il un moyen de faire ce que je veux ? Créer des objets dans une fonction et les stocker dans un tableau ?

  2. #2
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 265
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 265
    Points : 6 686
    Points
    6 686
    Billets dans le blog
    2
    Par défaut
    Effectivement, c'est un problème de scope (portée en français).
    Le code suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Chat c2 = Chat(2);
     
    // note: le code suivant est meilleur (bien que si tu as un bon compilateur, au final le code généré est le même):
    Chat c2(2);
    crée un objet Chat sur la pile. Donc dès que tu sort de la portée (dans ton cas, c'est la fonction setup()), cet objet est automatiquement détruit et donc lorsque tu tentes, plus tard, d'y accéder, tu te manges une seg fault.

    La meilleure solution que je vois, puisque tu ne peux pas utiliser new, c'est de créer une classe qui va contenir tes Chat et les gérer. Cette classe contiendra un tableau (qui contient les Chat), et quelques fonctions de manipulations selon tes besoins (addChat, deleteChat, etc.). Ainsi par exemple, lorsque tu fais un addChat(), tu crée directement ton nouveau Chat dans le tableau. Quelque chose dans le style:
    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
    #define MAX_CHATS 100
     
    struct MesChats
    {
        MesChats( int n ); //ctor
        addChat( const ); // ajouter un chat
        const Chat & getChat( int index ) const { return mes_chats_[index]; }
     
    private:
        Chat mes_chats_[MAX_CHATS];
        int nb_chats_; // nombre de chats existants
    };
     
    MesChats::MesChats()
    : nb_index(0)
    {}
     
    void MesChats::addChat( int n )
    {
        mes_chats_[nb_chats_].num = n;
        nb_chats_++;
    }
    Note: ce code est juste pour donner une idée, je ne l'ai même pas compilé.

  3. #3
    Invité
    Invité(e)
    Par défaut
    Bonjour,
    Cela semble curieux que le mot clé "class" soit autorisé et pas le mot clé "new", mais bon .
    A votre place j'écrirais une fonction à base de malloc pour remplacer new, en fait comme vous avez fait.

    Le problème de portée des variables est différent.
    Lorsque vous appelez Chat(2), vous créez un objet Chat à la position 2 de votre tableau poly, or la place n'a pas encore été allouée.
    Si vous voulez créer un animal à la position 2, soit il y en a déjà un et le nouvel animal remplacera l'ancien, soit il n'existe pas, alors il faut créer l'espace mémoire.
    On peut aussi distinguer Add(void) et Replace(rang).

  4. #4
    Membre chevronné
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Points : 1 921
    Points
    1 921
    Par défaut
    Fut un temps ou j'ai du gérer ce genre de truc sur un PIC. Le plsu simple a été de définir un allocateur qui allouer la mémoire statiquement et faisait des new de placement.

    http://codepad.org/zCJpArvT

    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
     
    #include <cstddef>
     
    template< class Type
            , std::size_t Size = 1024*1024
            , std::size_t ID = sizeof(Type)
            >
    struct heapless_allocator
    {
      static Type* allocate()
      {
        if( next+sizeof(Type) <= end )
        {
          Type* mem = new(next) Type;
          next += sizeof(Type);
          return mem;
        }
        else
         return 0;
      }
     
      static Type* allocate( std::size_t nb )
      {
        if( next+nb*sizeof(Type) <= end )
        {
          Type* mem = new(next) Type[nb];
          next += nb*sizeof(Type);
          return mem;
        }
        else
         return 0;
      }
     
      static void release( Type* ptr ) { ptr->~Type(); }
     
      static void release( Type* ptr, std::size_t nb )
      {
        // there is nb objects from there
        for(std::size_t i=0;i<nb;++i)  (ptr++)->~Type();
      }
     
      static unsigned char   buffer[Size*sizeof(Type)];
      static Type*  next;
      static Type*  end;
    };
     
    template<class Type, std::size_t Size, std::size_t ID>
    unsigned char heapless_allocator<Type,Size,ID>::buffer[Size*sizeof(Type)];
     
    template<class Type, std::size_t Size, std::size_t ID>
    Type* heapless_allocator<Type,Size,ID>::next 
       = (Type*)(&heapless_allocator<Type,Size,ID>::buffer[0]);
     
    template<class Type, std::size_t Size, std::size_t ID>
    Type* heapless_allocator<Type,Size,ID>::end 
       = (Type*)(&heapless_allocator<Type,Size,ID>::buffer[Size]);
     
    struct foo
    {
      foo() { cout << "allocating foo @" << this << endl; }
      ~foo() { cout << "deallocating foo @" << this << endl; }
    };
     
    int main()
    {
      foo* mem = heapless_allocator<foo,8>::allocate();
      cout << mem << endl;
      heapless_allocator<foo>::release(mem);
      cout << endl;
      mem = heapless_allocator<foo,8>::allocate(7);
      cout << mem << endl;
      heapless_allocator<foo>::release(mem,7);
      cout << endl;
      mem = heapless_allocator<foo,8>::allocate();
      cout << mem << endl;
      cout << endl;
    }
    L'idee est d'avoir un bon gros chunk de memoire static puis de placer ces objets dedans et d'en renvoyer l'adresse. le new de placement devrait fonctionner vu qu'il n'alloue rien de lui même.

    A noter la gestion de la mémoire plus que simpliste mais l'idée est la.

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Février 2005
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 52
    Points : 47
    Points
    47
    Par défaut
    Citation Envoyé par r0d Voir le message
    Effectivement, c'est un problème de scope (portée en français).
    Le code suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Chat c2 = Chat(2);
     
    // note: le code suivant est meilleur (bien que si tu as un bon compilateur, au final le code généré est le même):
    Chat c2(2);
    crée un objet Chat sur la pile. Donc dès que tu sort de la portée (dans ton cas, c'est la fonction setup()), cet objet est automatiquement détruit et donc lorsque tu tentes, plus tard, d'y accéder, tu te manges une seg fault.

    La meilleure solution que je vois, puisque tu ne peux pas utiliser new, c'est de créer une classe qui va contenir tes Chat et les gérer. Cette classe contiendra un tableau (qui contient les Chat), et quelques fonctions de manipulations selon tes besoins (addChat, deleteChat, etc.). Ainsi par exemple, lorsque tu fais un addChat(), tu crée directement ton nouveau Chat dans le tableau. Quelque chose dans le style:
    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
    #define MAX_CHATS 100
     
    struct MesChats
    {
        MesChats( int n ); //ctor
        addChat( const ); // ajouter un chat
        const Chat & getChat( int index ) const { return mes_chats_[index]; }
     
    private:
        Chat mes_chats_[MAX_CHATS];
        int nb_chats_; // nombre de chats existants
    };
     
    MesChats::MesChats()
    : nb_index(0)
    {}
     
    void MesChats::addChat( int n )
    {
        mes_chats_[nb_chats_].num = n;
        nb_chats_++;
    }
    Note: ce code est juste pour donner une idée, je ne l'ai même pas compilé.
    Je ne sais pas si j'ai bien saisie. Le problème c'est que je voudrais que mes animaux soient bien différents, pas seulement que leur numéros change.
    Ca m'a donné l'idée de tenter ça mais c'est toujours le même problème ...

    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
    class Animal
    {
    protected :
      int _num ;
     
    public :
      Animal(){
      }
      Animal( int num )
      {
        _num = num ;
      }
     
      virtual void parle() const=0 ;
    };
     
    class Chien :
    public Animal
    {
    public :
     
      Chien( int num ):
      Animal( num )
      {
      }
     
      virtual void parle() const
      {
        Serial.println("wouarf");
      }
    };
     
    class Chat :
    public Animal
    {
    public :
     
      Chat( int num ):
      Animal( num )
      {
      }
     
      virtual void parle() const
      {
        Serial.println("miaou");
      }
    };
     
    class Menagerie
    {
    private :
      int _nbBetes ;
      Animal * poly[20];
     
    public :
      Menagerie()
      {
        _nbBetes = 0 ;
      }
     
      void addChat(int num)
      {
        poly[_nbBetes++] = &Chat(num);
      }
      void addChien( int num )
      {
        poly[_nbBetes++] = &Chien(num);
      }
     
      void faitParler()
      {
        for( int i = 0 ; i < _nbBetes ; i++ )
        {
          poly[i]->parle();
          delay( 1000 );
        }
      }
    };
     
    Menagerie mesAnimaux = Menagerie() ;
     
    void setup()
    {
      Serial.begin(9600);
    }
     
    int etat = 0 ;
     
    void loop()
    {
      Serial.println( millis() );
     
      switch( etat )
      {
      case 0 :
     
        mesAnimaux.addChat(3);
        mesAnimaux.addChien(7);
     
        etat++ ;
        break ;
      case 1 :
     
        mesAnimaux.faitParler();
     
        break ;
      }
     
     
    }

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Salut,
    Citation Envoyé par Joel F Voir le message
    Fut un temps ou j'ai du gérer ce genre de truc sur un PIC. Le plsu simple a été de définir un allocateur qui allouer la mémoire statiquement et faisait des new de placement.

    http://codepad.org/zCJpArvT

    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
     
    #include <cstddef>
     
    template< class Type
            , std::size_t Size = 1024*1024
            , std::size_t ID = sizeof(Type)
            >
    struct heapless_allocator
    {
      static Type* allocate()
      {
        if( next+sizeof(Type) <= end )
        {
          Type* mem = new(next) Type;
          next += sizeof(Type);
          return mem;
        }
        else
         return 0;
      }
     
      static Type* allocate( std::size_t nb )
      {
        if( next+nb*sizeof(Type) <= end )
        {
          Type* mem = new(next) Type[nb];
          next += nb*sizeof(Type);
          return mem;
        }
        else
         return 0;
      }
     
      static void release( Type* ptr ) { ptr->~Type(); }
     
      static void release( Type* ptr, std::size_t nb )
      {
        // there is nb objects from there
        for(std::size_t i=0;i<nb;++i)  (ptr++)->~Type();
      }
     
      static unsigned char   buffer[Size*sizeof(Type)];
      static Type*  next;
      static Type*  end;
    };
     
    template<class Type, std::size_t Size, std::size_t ID>
    unsigned char heapless_allocator<Type,Size,ID>::buffer[Size*sizeof(Type)];
     
    template<class Type, std::size_t Size, std::size_t ID>
    Type* heapless_allocator<Type,Size,ID>::next 
       = (Type*)(&heapless_allocator<Type,Size,ID>::buffer[0]);
     
    template<class Type, std::size_t Size, std::size_t ID>
    Type* heapless_allocator<Type,Size,ID>::end 
       = (Type*)(&heapless_allocator<Type,Size,ID>::buffer[Size]);
     
    struct foo
    {
      foo() { cout << "allocating foo @" << this << endl; }
      ~foo() { cout << "deallocating foo @" << this << endl; }
    };
     
    int main()
    {
      foo* mem = heapless_allocator<foo,8>::allocate();
      cout << mem << endl;
      heapless_allocator<foo>::release(mem);
      cout << endl;
      mem = heapless_allocator<foo,8>::allocate(7);
      cout << mem << endl;
      heapless_allocator<foo>::release(mem,7);
      cout << endl;
      mem = heapless_allocator<foo,8>::allocate();
      cout << mem << endl;
      cout << endl;
    }
    L'idee est d'avoir un bon gros chunk de memoire static puis de placer ces objets dedans et d'en renvoyer l'adresse. le new de placement devrait fonctionner vu qu'il n'alloue rien de lui même.

    A noter la gestion de la mémoire plus que simpliste mais l'idée est la.
    Je n'exclus pas la possibilité de me tromper (surtout à l'heure à laquelle je poste cette réponse ), mais il me semble que, étant donné que tu incrémente next lors de allocate (ce qui est en soi tout à fait logique, pour éviter de renvoyer deux fois le même pointeur ), tu devrais le décrémenter de manière similaire dans la fonction release pour éviter de te retrouver au final avec... un tas d'objets inutilisables parce considérés comme libérés mais se trouvant à une adresse mémoire inférieure par rapport à next.

    Et encore, cela ne résoudrait qu'une partie du problème (ou nécessiterait au minimum une attention particulière quant à l'ordre des pointeurs sur lesquels on invoque release) dans le sens où la simple décrémentation du pointeur pourrait faire passer un objet encore utilisé pour... officiellement détruit

  7. #7
    Membre chevronné
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Points : 1 921
    Points
    1 921
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Salut,

    Je n'exclus pas la possibilité de me tromper (surtout à l'heure à laquelle je poste cette réponse ), mais il me semble que, étant donné que tu incrémente next lors de allocate (ce qui est en soi tout à fait logique, pour éviter de renvoyer deux fois le même pointeur ), tu devrais le décrémenter de manière similaire dans la fonction release pour éviter de te retrouver au final avec... un tas d'objets inutilisables parce considérés comme libérés mais se trouvant à une adresse mémoire inférieure par rapport à next.
    C'est délibéré. Le but du truc est de fournir un bloc de Size objet de type T ou Size est le nombre max d'objet de ce type necessaire à l'application dont l'alloc/dealloc soit rapide. Le choix d'avoir un gestionnaire d'espace libre complétement absent vient du fait que, bien souvent, tu te moques de libérer les objets avant la fin du programme. Autre point, l'ID devrait permettre de collapser tt les allocateur utilisant des objets d'un même sizeof et dans ce cas, le release ne peut rien faire d'autre que avancer.

    On peut bien entendu complexifié release et allocate pour ajouter une gestion plus fine du bloc libre mais à l'époque ou j'ai eu besoin de ça, le besoin n'etait pas là. En gros on chercher à detecter des speckels dans une image et le process demandait à virer la piéce si il y avait plus de 1000 speckles detecté sur la pièce et de renvoyer la position des speckles sinon. Le plus simple a été de d'avoir un conteneur façon vector mais utilisant un allocateur comme celui-çi avec un Size de 1000. Lorsque l'allocate echoué, on avait nos 1000 speckles.

    TLDR; pour faire court, l'idée de ce code etait de montrer qu'on pouvait s'en sortir avec un système d'allocation assez simple d'utilsiation sans new effectif.

  8. #8
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 265
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 265
    Points : 6 686
    Points
    6 686
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Tiberizz Voir le message
    Le problème c'est que je voudrais que mes animaux soient bien différents
    Ha ben là, si tu peux pas faire de new, alors tu ne peux pas faire ça directement. Puisque pour avoir des types différents dans un même conteneur, il faut que ce soient des pointeurs.
    Sinon, ce que tu peux faire c'est:
    1/ stocker tes Chat et Chien dans 2 tableaux, que nous appelerons MesChats et MesChients, dans des std::vector par exemple
    2/ déclarer un tableau de Animal* dont chaque élément pointera sur un élément des MesChats et MesChiens.

    C'est alambiqué et il y a beaucoup de faiblesses (potentialités d'erreurs donc) mais je ne vois pas d'autre solution.

Discussions similaires

  1. retour tableau d'objets par service web axis jboss
    Par TrollMaster dans le forum XML/XSL et SOAP
    Réponses: 6
    Dernier message: 27/11/2005, 21h45
  2. Tableau d'objets
    Par moulefrite dans le forum MFC
    Réponses: 7
    Dernier message: 15/06/2004, 14h14
  3. Sauvegarde / Chargement d'un tableau d'objets
    Par Naruto dans le forum Langage
    Réponses: 3
    Dernier message: 18/05/2004, 14h34
  4. [VB6]Tableau d'objet withevents
    Par soazig dans le forum VB 6 et antérieur
    Réponses: 8
    Dernier message: 13/02/2004, 19h44
  5. [VB6] [Syntaxe] Fonction renvoyant un tableau d'objets
    Par Troopers dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 18/10/2002, 15h33

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