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++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre émérite
    Avatar de Daïmanu
    Homme Profil pro
    Développeur touche à tout
    Inscrit en
    Janvier 2011
    Messages
    735
    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 : 735
    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.

  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 : 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
    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
    735
    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 : 735
    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.

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

  5. #5
    Membre Expert
    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 : 38
    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
    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.

  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
    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 Expert Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

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

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    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