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 :

Forcer le déplacement d'un objet incopiable


Sujet :

C++

  1. #1
    Membre émérite
    Avatar de Daïmanu
    Homme Profil pro
    Développeur touche à tout
    Inscrit en
    Janvier 2011
    Messages
    696
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur touche à tout

    Informations forums :
    Inscription : Janvier 2011
    Messages : 696
    Points : 2 438
    Points
    2 438
    Par défaut Forcer le déplacement d'un objet incopiable
    Bonjour.

    Je cherche à déplacer un objet incopiable dans un std::set pour que ce dernier en devienne le propriétaire, mais le code suivant provoque plusieurs erreur.
    Apparemment le compilateur a du mal avec la fonction variadique et la substitution d'arguments.

    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
    #include <set>
     
    struct Element {
    	Element(int i = 0) : i(i) {};
    	Element(Element const&) = delete;
    	Element(Element&&) = default;
    	int i;
    };
     
    bool operator < (const Element& Element1, const Element& Element2) {
    	return Element1.i < Element2.i;
    }
     
    struct Container {
    	std::set<Element> elems;
     
    	void addElements() {}
     
    	template<class ... Tail>
    	void addElements(Element const&& elem, Tail&& ... tail) {
    		elems.insert(elem);
    		addElements(std::forward<Tail>(tail)...);
    	}
    };
     
    int main(int, char**) {
    	Container container;
    	container.addElements(Element(9), Element(36));
     
    	Element elem = 25;
    	container.addElements(elem);
     
    	return 0;
    }
    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
    main.cpp: In function ‘int main(int, char**)’:
    main.cpp:31:28: error: no matching function for call to ‘Container::addElements(Element&)’
      container.addElements(elem);
                                ^
    main.cpp:31:28: note: candidates are:
    main.cpp:17:7: note: void Container::addElements()
      void addElements() {}
           ^
    main.cpp:17:7: note:   candidate expects 0 arguments, 1 provided
    main.cpp:20:7: note: template<class ... Tail> void Container::addElements(const Element&&, Tail&& ...)
      void addElements(Element const&& elem, Tail&& ... tail) {
           ^
    main.cpp:20:7: note:   template argument deduction/substitution failed:
    main.cpp:31:28: note:   cannot convert ‘elem’ (type ‘Element’) to type ‘const Element&&’
      container.addElements(elem);
     
    In file included from /**** blah blah ****/
    main.cpp:21:20:   required from ‘void Container::addElements(const Element&&, Tail&& ...) [with Tail = {Element}]’
    main.cpp:28:47:   required from here
    /usr/include/c++/4.9/ext/new_allocator.h:120:4: error: use of deleted function ‘Element::Element(const Element&){ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
        ^
    main.cpp:5:2: note: declared here
      Element(Element const&) = delete;
      ^
    Je voudrais savoir si il est possible de modifier Container pour qu'il déplace tout ce qui va dans addElements sans toucher au code client.
    J'ai déjà tenté de surcharger addElements(Element const&) sans plus de résultats.

    Cordialement.
    Je fais appel aux esprits de Ritchie, Kernighan, Stroustrup et Alexandrescu
    Donnez moi la force, donnez moi le courage de coder proprement !

    « Ça marche pas » n'est PAS une réponse convenable, merci de détailler le souci en fournissant l’environnement, le code source, les commandes et les messages d'erreur.

    Ce club possède également un clavardage, on y trouve quelques perles entre deux sessions d'entraides.

  2. #2
    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 : 49
    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
    Points : 16 213
    Points
    16 213
    Par défaut
    Le code suivant compile chez moi :
    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
    #include <set>
     
    struct Element {
    	Element(int i = 0) : i(i) {};
    	Element(Element const&) = delete;
    	Element(Element&&) = default;
    	Element &operator=(Element const &) = delete;
    	Element &operator=(Element &&) = default;
    	int i;
    };
     
    bool operator < (const Element& Element1, const Element& Element2) {
    	return Element1.i < Element2.i;
    }
     
    struct Container {
    	std::set<Element> elems;
    	void addElements() {}
     
    	template<class ... Tail>
    	void addElements(Element && elem, Tail&& ... tail) {
    		elems.insert(std::move(elem));
    		addElements(std::forward<Tail>(tail)...);
    	}
    };
     
    int main(int, char**) {
    	Container container;
     
    	container.addElements(Element(9), Element(36));
     
    	Element elem = 25;
    	container.addElements(std::move(elem));
     
    	return 0;
    }
    Quatre modifs :
    - Remplacer const && par &&
    - Quand dans une fonction sink (prenant un argument par &&), on veut transmettre cet argument à une autre fonction, ne pas oublier que cet argument a désormais un nom, et qu'il faut utiliser std::move pour le rendre déplaçable void f(MonType &&var) { g(std::move(var));}- Dans ton main, pour l'appel à un argument, tu utilises un objet non temporaire, donc besoin d'appeler move.
    - J'ai compléter ta classe avec les deux manquants de la règle des 5, parce que, même s'il n'interviennent pas ici, je n'ai pas envie d'avoir à raisonner avec des types trop tordus...
    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.

  3. #3
    Membre émérite
    Avatar de Daïmanu
    Homme Profil pro
    Développeur touche à tout
    Inscrit en
    Janvier 2011
    Messages
    696
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur touche à tout

    Informations forums :
    Inscription : Janvier 2011
    Messages : 696
    Points : 2 438
    Points
    2 438
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    - Dans ton main, pour l'appel à un argument, tu utilises un objet non temporaire, donc besoin d'appeler move.
    J'aurais espéré ne pas avoir l'imposer au code client, mais puisqu'il le faut.

    Citation Envoyé par JolyLoic Voir le message
    - J'ai compléter ta classe avec les deux manquants de la règle des 5, parce que, même s'il n'interviennent pas ici, je n'ai pas envie d'avoir à raisonner avec des types trop tordus...
    Je n'avais simplement pas envie de surcharger l'exemple.

    J'ai vraiment l'impression de patauger avec la move semantic , je peine à trouver de bon tutos dessus.

    Merci en tous cas.

    Cordialement.
    Je fais appel aux esprits de Ritchie, Kernighan, Stroustrup et Alexandrescu
    Donnez moi la force, donnez moi le courage de coder proprement !

    « Ça marche pas » n'est PAS une réponse convenable, merci de détailler le souci en fournissant l’environnement, le code source, les commandes et les messages d'erreur.

    Ce club possède également un clavardage, on y trouve quelques perles entre deux sessions d'entraides.

  4. #4
    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
    Peut-être une fonction wrapper pourrait faire le std::move. Par exemple, une fonction comme std::set::emplace().
    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

  5. #5
    Membre émérite
    Avatar de prgasp77
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Juin 2004
    Messages
    1 306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Points : 2 466
    Points
    2 466
    Par défaut
    Puisque ton constructeur n'est pas explicit, l'instruction suivante est valide container.addElements(42); : crée la rvalue Element(42) et la déplace.
    -- Yankel Scialom

  6. #6
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Citation Envoyé par Daïmanu Voir le message
    J'aurais espéré ne pas avoir l'imposer au code client, mais puisqu'il le faut.
    Pour info, ce fut une décision tout à fait volontaire par le comité d’empêcher ce genre de code de compiler :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Element elem = 25;
    container.addElements(elem); // move silencieux d'elem dans container
    La move semantic a été conçu de manière à interdire tout déplacement silencieux. Si un client veut déplacer un objet dans le container il doit explicitement utiliser std::move.

  7. #7
    Membre chevronné Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

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

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Points : 2 160
    Points
    2 160
    Par défaut
    Ou donner un temporaire comme l'a dit prgasp77
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    container.addElements(Element(25));

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

Discussions similaires

  1. Problème de déplacement d'un objet dessiné
    Par mhamedbj dans le forum Graphisme
    Réponses: 4
    Dernier message: 04/05/2012, 17h32
  2. [c#]Comment forcer la destruction d'un objet précédemment créé?
    Par Jayceblaster dans le forum Windows Forms
    Réponses: 5
    Dernier message: 24/07/2009, 14h29
  3. Réponses: 7
    Dernier message: 26/01/2007, 21h11
  4. Déplacement d'un objet dans un TPageControl
    Par nek_kro_kvlt dans le forum Delphi
    Réponses: 4
    Dernier message: 12/10/2006, 17h48
  5. Réponses: 10
    Dernier message: 01/12/2003, 23h17

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