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 :

Problème de std::move et héritage


Sujet :

Langage C++

  1. #1
    Membre à l'essai
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2011
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Octobre 2011
    Messages : 10
    Points : 11
    Points
    11
    Par défaut Problème de std::move et héritage
    J'essaye de comprendre comprendre comment le std::move fonctionne mais il y a quelques trucs qui m'échapent:

    J'ai le code suivant:
    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<iostream>
    #include<string>
     
    using namespace std;
     
    class I
    {
    	public:
    	virtual void Display() { throw "stop";}
    };
     
    class A: public I
    {
    	string _s;
    	public:
    	A():_s("Hey kéké! "){}
    	virtual void Display() { cout << _s << "A is in da house" << endl;}
    };
     
    I&& f()
    {
    	A a;
    	I&& i = std::move(a);
    	i.Display();
    	return std::move(i);
    }
     
    int main(int c, const char **argv)
    {
    	I&& i = f();
    	i.Display();
    	return 0;
    }
    Je compile ainsi:
    >g++ -std=c++11 -o sortie essai.cpp
    >./sortie
    Hey kéké! A is in da house
    A is in da house

    Pourquoi dans la fonction f I.Display retourne "Hey kéké! A is in da house" alors que dans la fonction main j'ai: "A is in da house"?

    Note:
    Je me dis que le problème ne vient peut être pas du std::move mais que dans la fonction f, le return n'est pas bon.

    J'ai réessayé de changé la fonction f ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    I&& f()
    {
    	A a;
    	//I&& i = std::move(a);
    	//i.Display();
    	return std::move(a);
    }
    Et lorsque j’exécute le programme, le i.Display() de la fonction main continue de retourner: "A is in da house"

  2. #2
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    La raison pour laquelle ton code ne fonctionne pas comme tu t'y attendrais est que ton instance de A est détruite quand tu sors de la fonction f(). Le fait que tu ait appelé std::move(a) est illusoire : ça ne fait que retourner une référence sur ton objet, et ça ne prolonge donc pas sa durée de vie. Le "mouvement" ne s'opère réellement que quand tu affecte ta référence à un autre objet.

    En principe tu n'as pas a retourner de r-value reference (I&&) à ta fonction :
    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
    #include <iostream>
    #include <string>
     
    struct A {
        A() = default;
     
        A(const A& a) : s(a.s) { std::cout << "A(copy)" << std::endl; }
        A& operator = (const A& a) { s = a.s; std::cout << "A = copy" << std::endl; }
     
        A(A&& a) : s(std::move(a.s)) { std::cout << "A(move)" << std::endl; }
        A& operator = (A&& a) { s = std::move(a.s); std::cout << "A = move" << std::endl; }
     
        std::string s;
    };
     
    A f() {
        A a;
        a.s = "test";
        return a;
    }
     
    int main(int argc, char* argv[]) {
        A a = f();
        std::cout << a.s << std::endl;
     
        return 0;
    }
    Si tu compile ça avec g++ -std=c++0x essai.cpp -o sortie -fno-elide-constructors (le -fno-elide-constructors désactive la "return-value optimization" pour mieux voir ce qui se passe), tu obtiens :
    A(move)
    A(move)
    test
    Donc sans utiliser std::move() une seule fois, le mouvement s'est fait automatiquement, sans aucune copie : un premier mouvement pour "sortir" a de la fonction, et un second pour le déplacer dans le a du main.
    Un bon exercice pour comprendre comment fonctionne la sémantique de mouvement est de déclarer le constructeur de copie et l'opérateur d'affectation comme delete, et de voir tout ce que tu peux faire avec ton objet. Ça te permet aussi de voir quand il est nécessaire d'utiliser explicitement std::move().

    Maintenant en ce qui concerne l'héritage, ce sont deux notions qui ne se marient pas très bien ensemble. C'est comme avec la copie : si on veut copier une classe polymorphique, il faut utiliser une méthode I::clone() virtuelle, qui sera ré-implémentée dans chaque classe fille. Si tu le souhaites, tu peux faire pareil avec une méthode I::move() que tu pourrais implémenter 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
    struct I {
        virtual ~I() = default;
        virtual I* move() = 0;
    };
     
    struct A : public I {
        std::string s;
     
        A* move() override {
            A* a = new A();
            a->s = std::move(s);
            return a;
        }
    };
    Mais l'intérêt est assez limité : en pratique, quand on utilise des classes polymorphiques, on les alloue dynamiquement (avec new, donc) : il est inutile de déplacer la classe toute entière, puisqu'on peut simplement déplacer le pointeur... (on utilisera d'ailleurs plutôt std::unique_ptr). Par contre si tu gères un programme un peu complexe où tu as plusieurs zones de mémoire distinctes (genre mémoire partagée dans les applications multi-processus ?), ça peut être intéressant.

  3. #3
    Membre à l'essai
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2011
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Octobre 2011
    Messages : 10
    Points : 11
    Points
    11
    Par défaut
    En effet je constate que tu as raison.
    J'ai essayé de ré-écrire le programme dans tous les sens mais le destructeur est systématiquement appelé dès qu'on sort du scope de f.
    merci de ton aide

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

Discussions similaires

  1. problème avec std::cin
    Par _LVEB_ dans le forum SL & STL
    Réponses: 4
    Dernier message: 20/02/2007, 00h35
  2. Problème avec std::vector
    Par dhoorens dans le forum SL & STL
    Réponses: 4
    Dernier message: 31/12/2006, 14h27
  3. Problème de std
    Par Sachiel31 dans le forum MFC
    Réponses: 11
    Dernier message: 06/07/2006, 09h10
  4. [Hibernate]Problème pour mapping d' un héritage
    Par K-Kaï dans le forum Hibernate
    Réponses: 6
    Dernier message: 29/06/2006, 14h28
  5. Problème avec std::Vector
    Par mister3957 dans le forum SL & STL
    Réponses: 8
    Dernier message: 16/02/2006, 10h18

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