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 :

push_back une anonymous struct dans un vector


Sujet :

C++

  1. #1
    Membre confirm�
    Homme Profil pro
    D�veloppeur du dimanche
    Inscrit en
    F�vrier 2013
    Messages
    154
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activit� : D�veloppeur du dimanche

    Informations forums :
    Inscription : F�vrier 2013
    Messages : 154
    Par d�faut push_back une anonymous struct dans un vector
    Bonjour,

    Je trouve le code suivant pas terrible :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    struct Base {};
     
    std::vector<Base*> vector;
     
    struct : Base {} derivedInstance; // struct sans type, mais avec un nom
     
    vector.push_back(&derivedInstance);
    J'aimerais rendre la chose un peu plus "g�n�rique", sans avoir � d�finir un nom � chaque fois que je veux ajouter une structure fille dans mon vector. Y aurait-il un moyen d'�crire quelque chose dans ce style l� ? :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    struct Base {};
     
    std::vector<Base*> vector;
     
    vector.push_back(new struct : Base {}); // struct sans type, et sans nom
    Merci

  2. #2
    Expert �minent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activit� : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par d�faut
    Salut,
    Citation Envoy� par MrPchoun Voir le message
    Bonjour,

    Je trouve le code suivant pas terrible :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    struct Base {};
     
    std::vector<Base*> vector;
     
    struct : Base {} derivedInstance; // struct sans type, mais avec un nom
     
    vector.push_back(&derivedInstance);
    J'aimerais rendre la chose un peu plus "g�n�rique", sans avoir � d�finir un nom � chaque fois que je veux ajouter une structure fille dans mon vector. Y aurait-il un moyen d'�crire quelque chose dans ce style l� ? :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    struct Base {};
     
    std::vector<Base*> vector;
     
    vector.push_back(new struct : Base {}); // struct sans type, et sans nom
    Merci
    Heu, excuses moi, mais, d'o� sors tu cette syntaxe infame
    Normalement, si tu as une hi�rarchie de classe proche de
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    class Base{
        /* ... */
    };
    class Derivee : public Base {
        /*...*/
    }
    tu peux envisager d'utiliser un code proche de
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    int main(){
        Base b;
        Derivee d;
        std::vector<Base *> tab;
        tab.push_back(&b);
        tab.push_back(&d);
        return 0;
    }
    MAIScela n'ira pas sans poser un certain nombre de probl�me, car les pointeurs que l'on trouvera dans tab ne seront valides que si b et d existent encore. Ainsi, si on fait en sorte que la port�e de tab soit "un tout petit peu plus grande" que celle des variables, en modifiant main pour qu'il ressemble � quelque chose 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
    16
    int main(){
        std::vector<Base *> tab;
        if(conditon){
            Base b;
            tab.push_back(&b); 
        }else{    //CRACK b es détruit ici... le pointeur équivalant dans tab est invalidé
            Derivee d;
            tab.push_back(&d);
       }//CRACK d es détruit ici... le pointeur équivalant dans tab est invalidé
        //tab existe toujours ici, mais les pointeurs qu'il contient sont tous invalides
        for(size_t i = 0;i<tab.size();++i){
            tab[i]->doSomething(); // BOUM :déréférencement d'une adresse invalide
                                   // ==>comportement indéfini (sans doute une erreur de segmentation
        }
        return 0;
    }
    Du coup, il faut s'assurer que la dur�e de vie des objets dont tu prend l'adresse pour les pointeurs d�passe la port�e dans laquelle ils sont cr��s, ce qui t'oblige � passer par l'allocation dynamique de la m�moire. un code 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
    int main(){
        std::vector<Base *> tab;
        if(conditon){
            Base  *b = new Base;
            tab.push_back(b);
            /*    OU    OU    OU 
            tab.push_back(new Base);
            */ 
        }else{   
            Derivee * d = new Derivee;
            tab.push_back(d);
            /*    OU    OU    OU
            Base * d = new Derivee;
            tab.push_back(&d);
                  OU    OU    OU
            tab.push_back(new Derivee);
       }
        for(size_t i = 0;i<tab.size();++i){
            tab[i]->doSomething(); 
        }
        /* N'oublions pas de libérer la mémoire allouée pour les pointeurs */
     
        for(size_t i = 0;i<tab.size();++i){
            delete tab[i];
        }
        return 0;
    }
    Seulement, le choix du moment o� il faut veiller � lib�rer la m�moire allou�e � un pointeur est tr�s rarement aussi simple que cela... De plus, C++ est un langage � exceptions et il se fait que les exceptions brisent totalement l'ordre d'ex�cution. Il est donc tr�s facile d'en arriver � des situations o� le fait qu'une exception a �t� lanc�e risque d'occasionner des fuites m�moires.

    C'est la raison pour laquelle la norme C++11 (l'avant derni�re en date) est arriv�e avec la notion de "pointeurs intelligents". Ce sont des classes qui ont le bon gout de prendre en charge la d�cision de lib�rer correctement la m�moire allou�e � un pointeur juste avant que l'on ne perte tout trace de l'adresse o� cette m�moire se trouve. Je ne pourrais donc que te conseiller particuli�rement vivement de t'y int�resser tr�s rapidement
    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

  3. #3
    Membre Expert
    Homme Profil pro
    Ing�nieur d�veloppement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    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 : 760
    Par d�faut
    Quand je vois un usage abusif de structure anonyme, je me dis qu'on ne veut pas des classes, mais des fonctions polymorphiques.

    @MrPchoun: Combien y a-t-il de fonctions virtuelles dans la classe de base ? Une ? Si oui, regarde std::function + lambda.

  4. #4
    Membre confirm�
    Homme Profil pro
    D�veloppeur du dimanche
    Inscrit en
    F�vrier 2013
    Messages
    154
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activit� : D�veloppeur du dimanche

    Informations forums :
    Inscription : F�vrier 2013
    Messages : 154
    Par d�faut
    @koala01 : par rapport aux deux premiers codes que tu as pondu : j'ai pas besoin de donner un nom � la structure, parce qu'il n'y a qu'une seule instance de cette structure dans mon vector, et dans tout mon programme d'ailleurs. En fait, le vector est rempli de structures uniques, qui d�rivent toutes de Base. Une autre fonction se charge de cr�er le contenu des classes d�riv�es (membres et fonctions sp�cifiques).
    Et je comprends tout � fait qu'il vaut mieux faire de l'allocation dynamique de m�moire et pas du r�f�rencement, pour les probl�mes que tu as point� (oh oh brillant jeu de mot), c'est d'ailleurs en fait l'objet de mon post, puisque cette solution ne me convenait pas (cf mon premier post). Et je connais bien �videment les smarts pointer, mais ils ne me sont d'aucune utilit�, parce que j'ajoute toutes mes structures d�riv�es dans mon vector au d�but du programme, et qu'ensuite �a ne bouge plus : aucun risque de suppression.

    @jo_link_noir : alors j'ai fini par faire �a, mais pas dans le sens o� tu l'entends je crois ! J'ai m�me fini par me passer des pointeurs d'ailleurs, par un petit tour de passe passe qui me surprend encore

    Je suis pass� par �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
     
        struct Base
        {
            std::function<void()> doSomething;
        };
     
        std::vector<Base> vector;
     
        struct Derived : Base
        {
            int a = 10;
     
            Derived()
            {
                doSomething = [this]
                {
                    std::cout<<a;
                };
            }
        };
     
        vector.push_back(Derived());
     
        vector[0].doSomething();
    Pour le transformer en �a :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
        struct Base
        {
            std::function<void()> doSomething;
        };
     
        std::vector<Base> vector;
     
        vector.push_back([](){ struct Derived : Base { int a = 10; Derived() { doSomething = [this] { std::cout<<a; }; } }; return Derived(); }());
     
        vector[0].doSomething(); // affiche 10
    Je suis donc pass� par une fonction lambda qui s'appelle elle m�me, qui cr�e la structure d�riv�e et qui en retourne une instance, celle qu'on mettra dans mon vector. Le nom de ma structure d�riv�e est local, dans la lambda, �a me va tr�s bien, j'ai pas � l'utiliser autre part.

    Ce qui me surprend, c'est qu'on a un vector de Base, avec des Derived dedans, et pourtant les Derived ont acc�s � leur membres, membres que n'ont pas Base (a). �a me semble bizare. Mais �a me convient.

  5. #5
    Expert �minent

    Femme Profil pro
    Ing�nieur d�veloppement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    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 202
    Par d�faut
    ils ont acc�s � leur membre tant qu'ils n'ont pas �t� mis dans le vector: le temps de l'ex�cution de la lambda.
    Apr�s, chaque Derived est utilis� pour initialiser (par copie) un Base.

    En fait, si tu essayais d'utiliser vector.emplace_back(), (sans passer par le constructeur de copie...) ca ne marcherait plus vraiment

  6. #6
    Membre confirm�
    Homme Profil pro
    D�veloppeur du dimanche
    Inscrit en
    F�vrier 2013
    Messages
    154
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activit� : D�veloppeur du dimanche

    Informations forums :
    Inscription : F�vrier 2013
    Messages : 154
    Par d�faut
    Mais le code que je viens d'�crire est "valide" ? Je veux dire, il est portable, avec tous les compilateurs, ou c'est juste clang qui m'accorde une faveur ?

  7. #7
    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
    Il est peut-�tre valide, mais je serais personnellement tr�s r�ticent vis � vis d�un tel code. De mani�re g�n�rale, je n�aime pas tout ce qui est anonyme, � l�exception des namespaces.

    C�est quoi le but ?

  8. #8
    Membre confirm�
    Homme Profil pro
    D�veloppeur du dimanche
    Inscrit en
    F�vrier 2013
    Messages
    154
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activit� : D�veloppeur du dimanche

    Informations forums :
    Inscription : F�vrier 2013
    Messages : 154
    Par d�faut
    Bah c'est m�me plus anonyme du coup, juste limit� au lambda..

    Le but : je me triture l'esprit pour faire un Entity Component System propre. Base, c'est un System. Derived, c'est un System qui traitera certaines Entity, en fonction de leurs Components. Et doSomething, c'est la fonction d'update. Voilou !

  9. #9
    Membre Expert
    Homme Profil pro
    Ing�nieur d�veloppement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    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 : 760
    Par d�faut
    Pas valide, la lambda fait r�f�rence � this qui n'est plus de type Derived. Par contre vector.push_back({[](){ struct Derived { A a = 10; void operator()(){ std::cout<<a; } }; return Derived(); }()}); fonctionne car doSomething est initialis� avec le foncteur (qui n'est plus un type d�riv�).

    Mais vector.push_back({[a=10] { std::cout<<a; } }); est beaucoup plus simple et lisible. (c++14)
    (Avec std::vector<std::function<void()>> vector;)

  10. #10
    Membre Expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    D�tails du profil
    Informations personnelles :
    Localisation : France, Paris (�le de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Par d�faut
    Citation Envoy� par MrPchoun Voir le message
    Ce qui me surprend, c'est qu'on a un vector de Base, avec des Derived dedans, et pourtant les Derived ont acc�s � leur membres, membres que n'ont pas Base (a). �a me semble bizare. Mais �a me convient.
    Ou pour le dire autrement, une fois dans le vector, ce ne sont plus des Derived mais uniquement des Base. Ca compile mais n'aura pas le comportement que tu attends, la nature sp�cialis�e des Derived et les donn�es qui vont avec sont perdus. Pour que cela fonctionne, il vaut mieux utiliser un vecteur d'unique_ptr (si tu veux que le vecteur soit propri�taire des objets, ce qui est le cas dans tes exemples) ou un vecteur de reference_wrapper ou de pointeurs.

  11. #11
    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
    Dans tous les cas, �a me parait un peu d�gueulasse.

    Comme je vois � Entity Component System propre �, je m�inqui�te un peu sur la pertinence de la piste. Apr�s, si c�est un d�tail d�impl�mentation tr�s localis�, �a peut se comprendre, mais si tout le syst�me repose sur ce genre de truc, et que c�est expos� � l�utilisateur final, alors il y a vraisemblablement un probl�me de conception.

  12. #12
    Membre confirm�
    Homme Profil pro
    D�veloppeur du dimanche
    Inscrit en
    F�vrier 2013
    Messages
    154
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activit� : D�veloppeur du dimanche

    Informations forums :
    Inscription : F�vrier 2013
    Messages : 154
    Par d�faut
    @jo_link_noir : oui, mais il n'y a pas qu'une seule fonction virtuelle dans Base !

    Dans tous les cas, �a me parait un peu d�gueulasse.
    J'appr�cie ton honn�tet�, c'est � la fois rigolo et s�v�re. Formul� comme �a, �a me va ^^

    Je propose quelque chose de moins d�gueulasse, du moins je crois, et je me r�sous au polymorphisme/pointeurs, pour �viter les probl�mes que soulignent jblecanard :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    struct Base {};
     
    std::vector<Base*> vector;
     
    [&](){ struct Derived : Base {int a; void doSomething() {std::cout<<a;} }; vector.push_back(new Derived); }();

  13. #13
    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
    Citation Envoy� par MrPchoun Voir le message
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    struct Base {};
     
    std::vector<Base*> vector;
     
    [&](){ struct Derived : Base {int a; void doSomething() {std::cout<<a;} }; vector.push_back(new Derived); }();
    Deux remarques :
    * Base devrait avoir un destructeur virtuel
    * dans ton vector, tu devrais stocker des unique_ptr et pas des pointeurs nus

    Pour le reste, je n�ai pas une vision suffisante du contexte .

  14. #14
    Membre confirm�
    Homme Profil pro
    D�veloppeur du dimanche
    Inscrit en
    F�vrier 2013
    Messages
    154
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activit� : D�veloppeur du dimanche

    Informations forums :
    Inscription : F�vrier 2013
    Messages : 154
    Par d�faut
    Vendu !

    Merci pour vos remarques

+ R�pondre � la discussion
Cette discussion est r�solue.

Discussions similaires

  1. R�ponses: 1
    Dernier message: 24/07/2009, 23h12
  2. Utiliser une classe personnelle dans un vector
    Par Mindiell dans le forum SL & STL
    R�ponses: 16
    Dernier message: 01/03/2007, 17h42
  3. passer unee struct dans un buffer (char *)
    Par baert dans le forum C++
    R�ponses: 2
    Dernier message: 20/02/2006, 21h49
  4. mettre un struct dans un vector
    Par Biosox dans le forum SL & STL
    R�ponses: 2
    Dernier message: 02/02/2006, 16h34
  5. implementer une struct dans un .c
    Par jamal dans le forum C
    R�ponses: 10
    Dernier message: 10/03/2005, 19h52

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