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 :

créer objets attributs d'une classe en nombre inconnu


Sujet :

C++

  1. #1
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2016
    Messages
    277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2016
    Messages : 277
    Points : 946
    Points
    946
    Par défaut créer objets attributs d'une classe en nombre inconnu
    Bonjour,

    j'ai affaire à une classe qui doit comporter en attribut des objets d'une autre classe, ou des pointeurs sur ces objets, mais dont le nombre est inconnu au moment où on lance la méthode (ce nombre est lu dans un fichier). J'ai utilisé le mot clé new pour créer dynamiquement le nombre d'objets requis, mais est-il possible de faire autrement?

  2. #2
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Bonjour,

    Le type d'objet qui stocke une quantité variable d'objets s'appelle std::vector ce type est un des premiers que l'on apprends alors que l'utilisation de l'opérateur new est réservée aux experts. Ton cours de C++ est vraiment bizarre!

  3. #3
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2016
    Messages
    277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2016
    Messages : 277
    Points : 946
    Points
    946
    Par défaut
    Citation Envoyé par dalfab Voir le message
    Bonjour,

    Le type d'objet qui stocke une quantité variable d'objets s'appelle std::vector ce type est un des premiers que l'on apprends alors que l'utilisation de l'opérateur new est réservée aux experts. Ton cours de C++ est vraiment bizarre!
    Salut.
    Je connais vector, mais ça n'a pas de rapport avec la problèmatique. Comme on me l'a déjà fait remarquer à juste titre, le mieux est de poster du code. Je ne l'ai pas sous la main dans l'immédiat mais je reviendrai.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,
    Citation Envoyé par Chezkele Voir le message
    Salut.
    Je connais vector, mais ça n'a pas de rapport avec la problèmatique.
    Et pourtant si, std::vector a bel et bien un rapport avec la problématique, même s'il n'est pas ** forcément ** évident au premier abord.

    Car toutes les collections de la bibliothèque standard qui permettent de gérer leur taille à l'exécution -- comprend qui peuvent contenir un nombre variable et défini à l'exécution d'élément -- ce qui correspond, en gros, à toutes les collections de la bibliothèque standard à l'exception de std::array, permettent depuis toujours d'ajouter la copie d'un élément existant, qui, contrairement à l'élément "original" (dont la durée de vie est généralement limitée) "survivra" aussi longtemps que la collection elle-même existe.

    De plus, toutes les collections concernées disposent depuis 2011 (cela fait quand même 11 ans, presque 12, il est donc largement temps de s'en rendre compte ) de la possibilité de créer "sur place" un nouvel élément qui sera ajouté à la collection sans avoir besoin d'être copié.

    Dans un cas comme dans l'autre, on peut donc effectivement dire que, quoi qu'il arrive, le simple fait de pouvoir maintenir "un nombre d'éléments qui n'est connu qu'à l'exécution" (par exemple, lorsqu'on lit un fichier) implique forcément la possibilité de créer ces éléments
    Avant 2011, nous aurions suivi une logique qui aurait été proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    On crée la collection qui nous convient (un std::vector, par exemple)
    TANT QUE (l'on arrive à extraire les données qui nous permettent de créer un élément)
        on crée l'élément à partir des données extraites
        on copie l'élément dans la collection
    FIN TANT
    on dispose ici d'un nombre d'éléments identique à celui dont on a pu extraire les données du fichier
    Depuis 2011, nous pouvons un tout petit peu modifier cette logique pour lui donner une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    On crée la collection qui nous convient (un std::vector, par exemple)
    TANT QUE (l'on arrive à extraire les données qui nous permettent de créer un élément)
        on crée "sur place" dans la collection un élément à partir des données extraites
    FIN TANT
    on dispose ici d'un nombre d'éléments identique à celui dont on a pu extraire les données du fichier
    Maintenant, il y a quand même deux questions à se poser: La première est de savoir si les attributs de ta classe peuvent être copiés.

    Ce sera le cas si les attributs en question on ce que l'on appelle une "sémantique de valeur".

    Si la réponse est positive, la deuxième question n'a plus vraiment de sens, car elle s'applique essentiellement au attributs qui ne s'accommoderaient pas de voir des copies d'eux-même se balader à gauche et à droite (du fait de ce que l'on appelle "par opposition" une "sémantique d'entité", dont l'un des point essentiels est de faire partie d'une hiérarchie de classes suite à une relation d'héritage).

    Dans ce cas, il faut en effet se poser la question de savoir "qui" sera effectivement le mieux placé pour prendre la décision de détruire un élément de la collection lorsque celui-ci devient inutile (on parle généralement de la propriété de l'élément concerné, au sens "de la responsabilité de maintenir cet élément en mémoire").

    Les réponses à ces questions dépendant exclusivement de la situation dans laquelle tu te trouves dans le cadre de ton projet, il t'appartient, et à toi seul, de les apporter. En fonction de celles-ci, les explications pourront se poursuivre
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Expert éminent sénior
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 361
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 361
    Points : 20 381
    Points
    20 381
    Par défaut
    Citation Envoyé par Chezkele Voir le message
    J'ai utilisé le mot clé new pour créer dynamiquement le nombre d'objets requis, mais est-il possible de faire autrement?
    si je comprends bien vous voulez compter le nombre de fois où une instance de classe est crée ?
    Si c'est le cas oui on peut utiliser un conteneur comme std::vector et la méthode size retournera le nombre d'instances.

  6. #6
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2016
    Messages
    277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2016
    Messages : 277
    Points : 946
    Points
    946
    Par défaut
    Merci pour vos réponse, et en particulier à koala01 qui m'a peut-être donné un bille improtante.
    J'ai mis les pointeurs sur les fameux objets dans un map. Mon problème n'est pas que je ne connais pas les collections (mais peut-être pas assez bien la façon de s'en servir. ).
    En parcourant le forum, j'ai vu le code d'un gars qui a fait un peu la même chose que moi. Il a une classe Game qui va déclarer un vecteur qui contient une liste de pointeurs sur une autre classe Character. Son code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    vector<Character*> listePersos;
     
    (...)
     
    Game::Game(){
       // Ici je crée une entrée  dans la liste
       this->listePersos.push_back(new Character());
    }
    Est-il possible de procéder autrement qu'en utilisant le mot clé new?

  7. #7
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2016
    Messages
    277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2016
    Messages : 277
    Points : 946
    Points
    946
    Par défaut
    Ok, je pense que j'ai la réponse dans le fil suivant:
    https://www.developpez.net/forums/d1...objets-boucle/

    Ca devrait le faire, je ne sais pas trop pourquoi je me suis pris la tête comme ça avec new.

  8. #8
    Expert éminent sénior
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 361
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 361
    Points : 20 381
    Points
    20 381
    Par défaut
    Citation Envoyé par Chezkele Voir le message
    Est-il possible de procéder autrement qu'en utilisant le mot clé new?
    bonsoir si le conteneur ne contient pas de pointeurs pas besoin; déclarer simplement std::vector<character> characters
    Par contre si on empile des pointeurs oui allouer avec new et bien faire les delete correspondants.

  9. #9
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2016
    Messages
    277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2016
    Messages : 277
    Points : 946
    Points
    946
    Par défaut
    Citation Envoyé par Mat.M
    Par contre si on empile des pointeurs oui allouer avec new et bien faire les delete correspondants.
    Créer l'objet, puis insérer dans le vecteur son adresse avec & n'est pas possible?

  10. #10
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Citation Envoyé par Chezkele Voir le message
    Créer l'objet, puis insérer dans le vecteur son adresse avec & n'est pas possible?
    C'est possible dans de rares cas, mais c'est extrêmement complexe.
    Si tu crées l'objet, et que tu garantis (au présent et y compris les évolutions futures) que l'objet créé persistera au moins aussi longtemps que ton std::vector<>, mémoriser l'adresse de cet objet fonctionnera.
    Mais si l'objet n'est pas persistant (est un temporaire, est une variable locale, est dans une collection persistante mais qui pourrait avoir ses itérateurs invalidés, ...) alors conserver l'adresse ne peut pas fonctionner.

    Le moyen le plus sûr est de stocker des std::unique_ptr<> dans le std::vector<>, car alors le std::vector<> devient le propriétaire des objets et on a la garantie que les pointeurs qu'il contient seront toujours valides.
    Mais si tu es sûr de la persistance des objets (le cas rare), il est surement plus "lisible" de stocker dans ton std::vector<> des std::reference_wrapper<> de ton objet plutôt que des pointeurs.
    Mémoriser des pointeurs est une très mauvaise idée.

  11. #11
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2016
    Messages
    277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2016
    Messages : 277
    Points : 946
    Points
    946
    Par défaut
    Citation Envoyé par dalfab Voir le message
    C'est possible dans de rares cas, mais c'est extrêmement complexe.
    Si tu crées l'objet, et que tu garantis (au présent et y compris les évolutions futures) que l'objet créé persistera au moins aussi longtemps que ton std::vector<>, mémoriser l'adresse de cet objet fonctionnera.
    Mais si l'objet n'est pas persistant (est un temporaire, est une variable locale, est dans une collection persistante mais qui pourrait avoir ses itérateurs invalidés, ...) alors conserver l'adresse ne peut pas fonctionner.

    Le moyen le plus sûr est de stocker des std::unique_ptr<> dans le std::vector<>, car alors le std::vector<> devient le propriétaire des objets et on a la garantie que les pointeurs qu'il contient seront toujours valides.
    Mais si tu es sûr de la persistance des objets (le cas rare), il est surement plus "lisible" de stocker dans ton std::vector<> des std::reference_wrapper<> de ton objet plutôt que des pointeurs.
    Mémoriser des pointeurs est une très mauvaise idée.
    Ok, le sujet est la persistence de l'objet. Quand je stocke directement un objet (pas un pointeur donc) dans un vector, qu'est-ce qui se passe au niveau mémoire qui fait que l'objet va persister même s'il n'est créé que "localement" (= dans la fonction membre où je le stocke dans le vecteur)?

  12. #12
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    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 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Citation Envoyé par Chezkele Voir le message
    Quand je stocke directement un objet (pas un pointeur donc) dans un vector, qu'est-ce qui se passe au niveau mémoire qui fait que l'objet va persister même s'il n'est créé que "localement"?
    Pour faire simple :
    • si tu as 1 tableau de pointeurs vector<X*> ou X**: tu devras allouer dynamiquement chaque objet et placer le pointeur dans le tableau. Et évidemment il faudra à la fin desallouer tous tes objets.
    • si tu as 1 tableau d'objets vector<X> ou X*: tu devras recopier ton objet dans ton tableau, attribut par attribut tab[i].att = obj.att. Sauf si tu as des attributs pointeur, tu n'as pas de désallocation à faire.


    Mais le truc , c'est que depuis 2011 et le C+11, on ne veut plus avoir de pointeur. Il faut passer par des pointeurs intelligents ("smart pointers" en anglais <- ) : std::unique_ptr et shared_ptr/weak_ptr.
    Toutes les considérations d'appartenance que parle @koala01, c'est juste pour savoir comment réagit ton pointeur intelligent lors d'1 affectation. Parce qu'avec 1 std::unique_ptr, tu as 1 seul propriétaire. Donc c'est normal que lors de l'affectation, le propriétaire soit changé et que ton pointeur intelligent n'est plus la propriété.

    std::reference_wrapper<> c'est 1 peu + subtil si je ne me trompe pas : c'est ton tableau qui a l'appartenance de ton objet (comme avec 1 objet et contrairement à 1 pointeur intelligent ou pas) mais ton objet se comporte comme 1 pointeur (intelligent ou pas) pour le passage de paramètres.

  13. #13
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Citation Envoyé par Chezkele Voir le message
    Ok, le sujet est la persistence de l'objet. Quand je stocke directement un objet (pas un pointeur donc) dans un vector, qu'est-ce qui se passe au niveau mémoire qui fait que l'objet va persister même s'il n'est créé que "localement" (= dans la fonction membre où je le stocke dans le vecteur)?
    Si ton vecteur contient des objets, ce que tu mets dans ton vecteur ce sont des objets. Donc quand tu remplis ton vecteur tu y places des copies de tes objets.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    std::vector<Character>  listePersos;  // contient des Character
    (...)
    Game::Game(){
       Character  car{};
       listePersos.push_back( car );      // recopie l'objet car dans le vecteur
       // à cet instant il y a 2 Character similaires, un dans le vecteur, un dans car
    }  // à cet instant car n'existe plus, sa copie est dans le vecteur
    En utilisant std::unique_ptr<>, l'objet est alloué dans le tas et le vecteur contient un pointeur propriétaire de l'objet
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    std::vector<std::unique_ptr<Character>>  listePersos;  // contient des pointeurs propriétaires d'un Character
    (...)
    Game::Game(){
       auto  up_car = std::make_unique<Character>();  // ici on créé l'objet et le pointeur sur l'objet
       listePersos.emplace_back( std::move(up_car) ); // transfert du pointeur dans le vecteur
       // à cet instant il y a 1 pointeur propriétaire d'un Character dans le vecteur, et un autre pointeur up_car désormais vide
       listePersos.pop_back();                       // supprime l'élément donc supprime le pointeur propriétaire donc supprime le Character
    }
    La seconde méthode paraît plus compliquée que la première, elle a pourtant des avantages:
    - il n'y a jamais de copie d'objets, en particulier les objets à sémantique d'entité ne doivent/peuvent pas être copiés.
    - d'où un gain en temps significatif si Character est gros.
    - on peut utiliser l'héritage et stocker des uniques pointeurs sur objets héritant de Character.

Discussions similaires

  1. Passer un objet comme attribut d'une classe
    Par Leduc08 dans le forum Ext JS / Sencha
    Réponses: 1
    Dernier message: 05/04/2011, 11h54
  2. Réponses: 10
    Dernier message: 25/05/2010, 14h25
  3. Réponses: 14
    Dernier message: 07/03/2010, 20h08
  4. Récupérer le nombre et le type d'attribut d'une class
    Par adurandet dans le forum Langage
    Réponses: 5
    Dernier message: 27/11/2009, 18h19
  5. Créer une liste d'objets statiques dans une classe
    Par crossbowman dans le forum C++
    Réponses: 3
    Dernier message: 13/03/2006, 09h11

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