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 :

Lister toutes les instances d'une classe


Sujet :

Langage C++

  1. #1
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut Lister toutes les instances d'une classe
    Bonjour,

    Pour une raison que vous ne préférez pas connaitre, j'aimerais garder une liste de toutes les instances d'une classe. J'ai écrit un code comme ceci :

    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
    #include <algorithm>
    #include <iostream>
    #include <vector>
     
    struct Foo {
    	static std::vector<Foo*> instances;
     
    	static void list() {
    		std::cout << "---" << std::endl;
    		for (auto& foo : instances) {
    			std::cout << foo->name << std::endl;
    		}
    		std::cout << "---" << std::endl;
    	}
     
    	Foo(std::string name) :
    			name(name) {
    		instances.push_back(this);
    	}
     
    	Foo(const Foo&) = delete;
    	Foo& operator=(const Foo&) = delete;
     
    	~Foo() {
    		auto endIt = std::remove(instances.begin(), instances.end(), this);
    		instances.erase(endIt, instances.end());
    	}
     
    	std::string name;
    };
     
    std::vector<Foo*> Foo::instances;
     
    int main(void) {
    	{
    		Foo a { "a	" }, b { "b" }, c { "c" };
    		Foo::list();
    		{
    			Foo d("d");
    			Foo::list();
    		}
    		Foo::list();
    	}
    	Foo::list();
    }
    Il affiche :
    ---
    a	
    b
    c
    ---
    ---
    a	
    b
    c
    d
    ---
    ---
    a	
    b
    c
    ---
    ---
    ---
    
    - Quels commentaires pourriez-vous faire sur ce code ? Il n'est pas thread-safe mais ce n'est pas un problème ici.

    - Quels conteneurs auraient été mieux ?

    - Ma technique de suppression d'un élément du vector est-elle correcte ?

    Merci d'avance !

    EDIT : je rends compte que l'effacement d'un seul élément se fait très bien comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    		std::remove(instances.begin(), instances.end(), this);
    		instances.pop_back();

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Salut,

    y'a pas beaucoup d'options pour faire une telle chose.
    N'oublie pas d'aussi supprimer les constructeurs et affectation par déplacement. Mais ceci va bloquer l'utilisation de ta classe dans uen collection... Du coup tu devras surement implémenter le constructeur de déplacement, mais laisser l'affectation supprimée.
    Sinon, le constructeur de déplacement ne faisant pas l'insertion dans la liste, ton destructeur va supprimer la dernière instance de ta liste à cause du pop_back.
    Après la seule chose éventuellement à modifier c'est d'utiliser un set au lieu d'un vector. Mais faut vérifier si ça apporte un gain ou non. Ca va dépendre aussi du nombre d'instances que tu comptes avoir, et à quelle fréquence tu en ajoutes/supprimes et lesquelles (fin de liste ? début ? milieu ?).
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Pour la suppression, si l'ordre n'est pas important, mettre le dernier élément à la place de celui trouvé puis faire un pop_back sera plus rapide.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    *std::find(instances.begin(), instances.end(), this) = instances.back();
    instances.pop_back();

  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,

    Moi, je n'ai qu'un seul commentaire à faire : tu ne respecte pas le SRP

    Si tu veux garder "quelque part" une trace de toutes les instances de ta classe, tu devrais prévoir "quelque chose" dont ce serait la seule responsabilité (un FooHolder, peut-être ), et qui ne serait pas forcément accessible depuis ta structure Foo.

    Cela peut nécessiter quelque aménagements, comme le fait de clairement séparer les responsabilités en quelque chose comme
    • FooHolder : maintient les Foo qui sont créées (et les détruit quand elles sont inutiles)
    • FooFactory : crée des Foo à la demande
    • "QueqlueChose" qui fait le lien entre FooHolder et FooFactory et qui permet de créer des Foo à la demande et d'accéder aux Foo existants (interface : begin, end, find, add, remove, ...)


    J'ai bien conscience que cela peut sembler quelque peu "overkill", mais si tu commence à mélanger le tout en ajoutant des fonctions statiques à ta structure uniquement pour être en mesure de dresser "de temps en temps" la liste des instances existantes, toi et ton équipe aurez tendance à "profiter" de cette opportunité pour commencer à le faiire "n'importe où" à peu près "en dépis du bon sens".

    Et le résultat ne se fera pas attendre : Tu auras très rapidement de nombreux endroits où tu observeras une dépendance vis à vis de ta structure, alors qu'elle n'aurait normalement pas eu lieu d'être
    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
    Membre éprouvé
    Homme Profil pro
    Ingénieur R&D
    Inscrit en
    Mai 2016
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Ingénieur R&D
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2016
    Messages : 313
    Points : 1 237
    Points
    1 237
    Par défaut
    Il faut voir quel est l'usage. Il m'est arrivé de faire ce genre de chose, code du même type que bktero, provisoirement en debug, pour traquer des fuites de mémoire, mais ce code disparaissait ensuite, et donc il n'était pas utile de construire des structures plus élaborées (et même en C++ 11, où ce genre de méthode est en principe moins utile, je garde quand même parfois un compteur d'instances, juste un entier statique incrémenté/décrémenté, sans conserver les instances elles-mêmes, ça ne coûte pas très cher).

  6. #6
    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
    Pour du code "jetable", parce que tu as, pour un "très court instant", besoin de "plus d'informations" que ce que dont tu peux disposer en débug, je ne dis pas forcément le contraire

    Le problème, c'est quand le ce code (soit disant) jetable est prévu pour être utilisé "provisoirement" (un "hack" pour faire fonctionner quelque chose).

    Par ce que ce code "provisoire" aura la facheuse tendance à se transformer en code "définitivement provisoire", sur lequel s'appuiront de plus en plus de fonctionnalités au fil du temps, ce qui en rendra le retrait encore plus difficile.

    C'est le typique exemple de ce qui pourrait rapidement devenir une belle "dette technique": en voulant gagner cinq ou dix (ou même, mettons 60, vu qu'il y a tout un système à mettre en place), on va perdre, au fil du temps, des jours entiers à essayer de contourner et / ou de résoudre des problèmes qui ne seront apparus que parce que tu as fait ce choix malheureux

    Quand j'étais ambulancier, l'une de nos phrases fétiches était "vite, mais sans précipitation". Cela signifiait que l'on ne devait "pas trainer" à faire ce que l'on avait à faire (parce qu'on tenait parfois littéralement la vie de certaines personnes entre nos mains), mais que l'on ne devait pas se précipiter, car il suffisait que l'on trébuche (quand cela ne signifiait pas avoir un accident avec l'ambulance) pour perdre encore plus de temps que ce que l'on espérait gagner en le faisant.

    Je sais très bien que certains gestionnaires financiers vont râler si on passe plus de trois minutes à faire quelque chose qui leur semble simple. Mais si les développeurs en général devraient aussi comprendre que "que va piano va sano"
    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

  7. #7
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Prends garde que des instances peuvent aussi être créées par les constructeurs de déplacement.
    Supprimer la copie ne supprime pas le déplacement, c'est d'ailleurs exactement ce que font les *streams et unique_ptr.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  8. #8
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Citation Envoyé par ternel Voir le message
    Supprimer la copie ne supprime pas le déplacement
    Si, à partir du moment qu'une fonction de copie existe, l'équivalent par déplacement est cachée. Il faut alors mettre =default pour la rendre accessible.

Discussions similaires

  1. WMI : Nom de toutes les instance d'une classe
    Par Chachane dans le forum C++
    Réponses: 1
    Dernier message: 02/07/2010, 15h34
  2. Lister les instances d'une classe
    Par PierreLog dans le forum Général Python
    Réponses: 7
    Dernier message: 04/09/2009, 08h23
  3. Utilisation de toutes les instances d'une classe dans un while
    Par canaboss dans le forum Débuter avec Java
    Réponses: 12
    Dernier message: 28/04/2008, 15h28
  4. Accéder à toutes les instances d'une classe
    Par MrGecko dans le forum Delphi
    Réponses: 15
    Dernier message: 14/05/2007, 00h50
  5. Connaitre toutes les instances d'une classe
    Par miniseb dans le forum Langage
    Réponses: 14
    Dernier message: 09/01/2006, 17h35

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