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 :

vector<unique_ptr<>> et initializer_list


Sujet :

Langage C++

  1. #1
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut vector<unique_ptr<>> et initializer_list
    Bonjour

    Pas de problème avec les liste d’initialisation avec un vecteur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::vector<int> v { 1, 2, 3 };
    Pas de problème avec les liste d’initialisation avec un vecteur de pointeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::vector<int*> v { new int(1), new int(2), new int(3) };
    Pas de problème avec les liste d’initialisation avec un vecteur de shared_ptr :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::vector< std::shared_ptr<int> > v { std::make_shared<int>(1), std::make_shared<int>(2), std::make_shared<int>(3) };
    Problème avec les liste d’initialisation avec un vecteur d'unique_ptr :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::vector< std::unique_ptr<int> > v { ??? };
    Quelqu'un a une idée si c'est possible et quelle serait la syntaxe ?

  2. #2
    Expert confirmé

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 032
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Software Developer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 032
    Billets dans le blog
    12
    Par défaut
    unique_ptr ne peut pas être mis dans un conteneur de la stl car il n'a pas de constructeur par copie (par définition du unique_ptr)

    EDIT : J'ai été un peu vite, ce que j'ai dit est valide pour les scoped_ptr, je ne suis pas sur que ça le soit pour les unique_ptr
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

  3. #3
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    D'après Microsoft, un unique_ptr<> peut être déplacé, mais pas copié, donc c'est mort.

    La seule solution serait que les conteneurs standards C++ puissent avoir des arguments d'un type différent de leur contenu, comme les collections de Microsoft Foundation Classes (MFC). Je ne sais pas pour C++1x, mais je sais que ça n'est pas le cas en C++ "vieux".
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  4. #4
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par défaut
    Citation Envoyé par dragonjoker59 Voir le message
    unique_ptr ne peut pas être mis dans un conteneur de la stl car il n'a pas de constructeur par copie (par définition du unique_ptr)

    EDIT : J'ai été un peu vite, ce que j'ai dit est valide pour les scoped_ptr, je ne suis pas sur que ça le soit pour les unique_ptr
    unique_ptr<> n'est pas CopyConstructible, ni CopyAssignable - cf. 20.9.10§5 de N3126.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  5. #5
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut
    Je suis un peu étonné par vos réponses...

    Elles semblent répondre à la question "est-il possible d'utiliser unique_ptr dans un std::vector" et la réponse semble être "non".
    Comme ma question portait sur les listes d'initialisation un vector<unique_ptr>, c'est que j'ai déjà testé sans les listes et ça fonctionne très bien

    Un exemple de code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    std::vector< std::unique_ptr<A> > v;
     
    v.push_back(std::move(std::unique_ptr<A>(new A(1))));
    v.push_back(std::move(std::unique_ptr<A>(new A(2))));
    v.push_back(std::move(std::unique_ptr<A>(new A(3))));
     
    for (int i=0; i<v.size(); ++i)
       std::cout << i << " - " << v[i]->x << std::endl;
    ce qui fonctionne sans problème (gcc 4.5)

    D'où les questions suivantes :
    - Même si le code précédent compile, il "tombe en marche" et il ne faut pas l'utiliser ?
    - Quels sont les limites ? On obtient évidement un vecteur non copiable, ce qui interdit la copie du vecteur, mais rien de surprenant la dedans.
    - Quel serait les risques ?
    - Depuis le temps qu'on nous répète qu'il ne faut pas utiliser des pointeurs nus, voilà que maintenant, on ne peut pas les utiliser dans un conteneur... C'est un peu contradictoire, non ? Et en complément avec la préférence pour le passage par référence, ça limite quand même beaucoup l'intérêt des smart pointeurs.

  6. #6
    Membre Expert

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Par défaut
    Edit : En relisant je m'aperçois d'une chose. Vu que le problème de gbdivers et lié aux unique_ptr, je pars du principe dans la suite du post que le contexte est C++0x.
    ----------------------------------------------------------------------

    Bonjour,
    Il n'y a absolument aucun problème à placer des unique_ptr dans des conteneurs, seulement il faut les déplacer, pas les copier car les unique_ptr sont déplaçables uniquement. Donc, gbdivers, ton code avec les std::move est parfaitement correct. Plus généralement, la restriction minimum pour les objets placables dans un conteneur en C++03 étaient d'être CopyConstructible. Cette restriction a été diminué en C++0X à MoveConstructible seulement.

    Citation Envoyé par gbdivers
    Quels sont les limites ? On obtient évidement un vecteur non copiable, ce qui interdit la copie du vecteur, mais rien de surprenant la dedans.
    En effet, le vecteur n'est plus copiable. Il est par contre naturellement toujours déplaçable.

    Citation Envoyé par gbdivers
    - Quel serait les risques ?
    Contrairement aux auto_ptr, le risque est minime. Car le gros problème de l'auto_ptr était que son copy constructor était en fait... un déplacement déguisé ! Vu que les conteneurs et les algorithmes de la STL partent du principe qu'une copie... et bien fait réellement une copie, on pouvait se prendre des crashs lorsqu'un algo essayait d'accéder à un pointeur qui n'était plus là.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    std::auto_ptr<int> ptr1(new int(2));
    std::auto_ptr<int> ptr2(ptr1); // Une copie ? non, un déplacement fourbe !
    *ptr1 = 3; // BOUM
    Là encore ça va, on voit vite l'erreur, mais dans du code générique où l'on ne sait même pas que l'on manipule des auto_ptr...

    Avec les unique_ptr, rien de tout ça, car tout déplacement doit être clairement signalé par un std::move et une copie d'un objet move-only échoue à la compilation. On peut toujours se tirer une balle dans le pied mais il faut maintenant explicitement le demander
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    std::unique_ptr<int> ptr1(new int(2));
    std::unique_ptr<int> ptr2(std::move(ptr1)); // déplacement explicite
    *ptr1 = 3; // BOUM
    Même dans du code générique, on verrait bien qu'on a fait une boulette vu qu'on déplace un objet 1 dans un objet 2 puis on essaye d'utiliser l'objet 1....

    Donc en résumé : Il est parfaitement possible de placer des objets move-only dans des conteneurs et toutes les fonctions de la STL sont applicables sur de tel conteneurs. (sauf bien sur les algos qui ont intrinsèquement besoin de faire des copies, comme... std::copy , mais dans ce cas la compilation échoue.)


    Pour en revenir aux initializer_list et à leur interaction avec les unique_ptr :

    Malheureusement, je suis quasi certain qu'il est impossible de placer des unique_ptr dans des initializer_list.
    En fait, Les initializer_list et la sémantique de déplacement sont méchamment incompatibles car les initializer_list sont parfaitement immutables :

    - impossible de modifier une initializer_list qui est const par défaut.
    - donc connaissance complète à la compilation. Le but étant par exemple dans l'embarqué que les compilateurs puissent placer les initializer_list en ROM.
    - toutes les fonctions membres d'un initializer_list sont const ou bien renvoi des pointeurs const.
    - Le résultat c'est que l'utilisation d'une initializer_list pour initialiser un conteneur oblige à copier les éléments de l'initializer_list au conteneur.

    Si je me souviens bien, il y a quand même eu un proposal il y a quelques années pour proposer des "mutable_initializer_list", c'est à dire des intializer_list modifiable au run-time, donc pouvant contenir des objets move-only, mais qui n'a apparemment pas abouti.

    ...
    Tout ça est quand même assez ironique au final. Les initializer list ont été fortement poussé par Stroustrup lui-même car il voulait simplifier et homogénéiser l'initialisation en C++. En particulier, gommer la différence déroutante entre l'initialisation autorisée des POD en {} alors que non autorisé pour les conteneurs standards. Sauf qu'au final, avec les initializer_list on se retrouve dans une situation typique du C++ : une règle générale qui semble marcher à tout les coups jusqu'à ce qu'on tombe sur une exception qui nous explose à la figure, avec je suppose un message d'erreur incompréhensible, et le seul moyen de s'en sortir est de posséder des connaissances assez pointu - ici sur la sémantique de déplacement - pour comprendre les tenants et aboutissants de l'erreur.

  7. #7
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par Arzar Voir le message
    Tout ça est quand même assez ironique au final. Les initializer list ont été fortement poussé par Stroustrup lui-même car il voulait simplifier et homogénéiser l'initialisation en C++. En particulier, gommer la différence déroutante entre l'initialisation autorisée des POD en {} alors que non autorisé pour les conteneurs standards. Sauf qu'au final, avec les initializer_list on se retrouve dans une situation typique du C++ : une règle générale qui semble marcher à tout les coups jusqu'à ce qu'on tombe sur une exception qui nous explose à la figure, avec je suppose un message d'erreur incompréhensible, et le seul moyen de s'en sortir est de posséder des connaissances assez pointu - ici sur la sémantique de déplacement - pour comprendre les tenants et aboutissants de l'erreur.
    Disons qu'il y avait deux philosophies, parfois contradictoires, dans C++0x : En faire un langage plus simple, plus régulier (Bjarne était un des principaux ambassadeurs de cette philosophie), et en faire un langage plus puissant principalement pour faire des bibliothèques encore plus avancées (on va dire que Boost était très moteur sur ce point).

    J'ai l'impression qu'on est dans une situation typique où ce n'est pas hyper gênant (mais un peu gênant quand même, je l'accorde) : initializer_list est surtout destiné à des protos, des programmes de tests unitaire, des programmes d'apprentissage. unique_ptr, comme tout ce qui est lié à la move semantic, est plus à l'usage d'experts dans des bouts de code critiques ou des bibliothèques haut niveau. Dit autrement, je ne suis pas certain que l'on trouve beaucoup d'occasions de faire des initializer_list de unique_ptr (ou de tout autre type non copiable), peut-être pas assez pour justifier un autre mécanisme.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  8. #8
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    @gbdivers: Alors, c'est que le code des conteneurs a été lui aussi modifié pour accepter la move_semantics: Avant C++1x, les conteneurs ne marchaient que par copie.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut
    Merci pour vos réponses.

    En effet, les conteneurs ont été modifié pour ajouter la move_semantics et les initializer_list (et probablement d'autres choses, je découvre encore)

    Oui JolyLoic, c'est purement didactique pour moi pour découvrir c++1x. Je n'ai pas en pratique de code où j'initialise le contenu d'un vecteur dès sa création (et donc pour lequel je pourrais utiliser un initializer_list)

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

Discussions similaires

  1. Réponses: 19
    Dernier message: 29/09/2014, 17h12
  2. Utilisation de range-for sur un vector<unique_ptr>
    Par gbdivers dans le forum Langage
    Réponses: 3
    Dernier message: 19/10/2011, 18h09
  3. equivalent Vector du jsp
    Par Djib dans le forum ASP
    Réponses: 4
    Dernier message: 05/12/2003, 08h07
  4. "vector" provoque "syntax error", malgré
    Par seenkay dans le forum Autres éditeurs
    Réponses: 5
    Dernier message: 24/08/2003, 03h21
  5. Réponses: 2
    Dernier message: 11/07/2003, 18h24

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