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 :

Comment forcer la copie d'une classe?


Sujet :

Langage C++

  1. #1
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut Comment forcer la copie d'une classe?
    Bonjour,

    je cherche à forcer la copie d'une instance sur un retour de fonction, mais je n'y arrive pas !
    Je sais que ça n'a pas vraiment de sens, mais c'est juste parce que je voudrais tester un truc.
    Prenons 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
    class Foo
    {
    public:
    	Foo(int num = 10) : m_num(num) {}
     
    	Foo(const Foo& other) : m_num(other.m_num) {}
    	Foo(const Foo&& other) = delete;
     
    	Foo& operator = (const Foo& other) = delete;
    	Foo& operator = (const Foo&& other) = delete;
     
    	int m_num = 5;
    };
     
    Foo f(const Foo& foo1) 
    {
    	return Foo(foo1.m_num + 1);
    }
     
    int main()
    {
    	Foo foo1;
    	Foo foo2 = f(foo1);
    }
    Ça ne compile pas : il veut absolument son move ctor !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Error	C2280	'Foo::Foo(const Foo &&)': attempting to reference a deleted function
    Je travaille avec Visual Studio 2017.
    Merci par avance
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  2. #2
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Ca compile avec mingw64... mais clang-tidy me mets des erreurs similaires aux tiennes...

  3. #3
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Bonjour,

    En C++14 ça ne doit pas compiler (il faut une copie qui a été interdite), par contre en C++17 ça devrait compiler (on doit créer directement l'objet résultat.)

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Peut-être stupide mais essayes de retourner un const ? Le const devrait empêcher le déplacement.
    Après vue que tout va dans le sens d'éliminer les copies (move, RVO), vouloir le forcer est un peu étrange et pas forcément simple.
    Ne peux-tu pas passer une instance en paramètre out ? Créer un objet container ?

    Foo& operator () (const Foo& other) = delete; ce n'est pas plutôt l'operator = pour empêcher la copie que tu veux bloquer ?
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  5. #5
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par dalfab Voir le message
    par contre en C++17 ça devrait compiler
    Je compile effectivement en C++17 !

    Et je viens de tester en C++14 : ça ne compile pas ! Bien vu !

    Tu as une explication précise à ce cas à nous donner stp ?

  6. #6
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Foo& operator () (const Foo& other) = delete; ce n'est pas plutôt l'operator = pour empêcher la copie que tu veux bloauer ?
    Bien vu; j'ai édité.

    Citation Envoyé par Bousk Voir le message
    Peut-être stupide mais essayes de retourner un const ? Le const devrait empêcher le déplacement.
    nope, ça change rien avec VS 2017.

    Citation Envoyé par Bousk Voir le message
    Après vue que tout va dans le sens d'éliminer les copies (move, RVO), vouloir le forcer est un peu étrange et pas forcément simple.
    Ne peux-tu pas passer une instance en paramètre out ? Créer un objet container ?
    Ben oui le problème est bien là : j'essaie de faire quelque chose dont les concepteurs du langage mettent tout en œuvre depuis plusieurs d'années pour que je ne puisse pas le faire ! ^_^
    J'aimerais éviter de passer par des intermédiaires. En fait, c'est pour "tester" notre profiler (un outil interne). J'ai l'impression qu'il fait des trucs bizarres et j'essaie de le piéger. Il fait une sauce à lui qui mélange analyse statique et des trucs au runtime.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Et retourner un pointeur ?
    Tu peux ensuite déréférencer le pointeur pour faire ta copie. Avec unique_ptr tu n'as pas à te soucier de la mémoire.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  8. #8
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Tu as une explication précise à ce cas à nous donner stp ?
    En fait j'ai répondu un peu vite. En C++14 ça devrait aussi compiler car le constructeur par déplacement n'existe pas, mais il devrait pouvoir se rabattre en utilisant le constructeur de copie qui lui est accessible. En C++17 il n'a même pas besoin de regarder les constructeurs de copie, on sait créer l'objet donc on peut avoir une fonction qui retourne l'objet, la RVO est désormais obligatoire même si l'objet n'a pas de constructeur de copie.
    La ligne return f( foo1.m_num + 1 ); peut être remplacée par return { foo1.m_num + 1 };, on contourne ici la construction explicite d'un objet à copier, mais pourquoi le constructeur par copie ne serait pas utilisé ici? Je ne vois pas pourquoi c'est refusé.
    La ligne Foo foo2 = f(foo1); devrait être optimisée, sinon peut toujours écrire Foo&& foo2 = f(foo1); pour que foo2 corresponde à ce qui est retourné par la fonction f.

  9. #9
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    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 : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Citation Envoyé par dalfab Voir le message
    En fait j'ai répondu un peu vite. En C++14 ça devrait aussi compiler car le constructeur par déplacement n'existe pas, mais il devrait pouvoir se rabattre en utilisant le constructeur de copie qui lui est accessible.
    Ce n'est pas qu'il n'existe pas, bien au contraire, c'est qu'il n'est pas autorisé. Le même comportement existe avec n'importe quelles fonctions.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void foo(int const&){}
    void foo(int const&&) = delete;
     
    foo(1); // refusé
    int i;
    foo(i); // ok
    Pour que le constructeur de déplacement ne soit pas utilisé, il faut uniquement le constructeur de copie.

    Citation Envoyé par dalfab Voir le message
    La ligne return f( foo1.m_num + 1 ); peut être remplacée par return { foo1.m_num + 1 };, on contourne ici la construction explicite d'un objet à copier, mais pourquoi le constructeur par copie ne serait pas utilisé ici? Je ne vois pas pourquoi c'est refusé.
    Cette forme fait aussi partie de la RVO. En fait, le changement en 17 ne s'applique pas spécialement à la RVO, mais à l’élision de copie en général.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Foo f = Foo{Foo{Foo{}}}; // élision, pas de copie
    Foo f(const Foo& foo1)
    {
        Foo f(foo1.m_num + 1);
        return f;  // élision (valide aussi en 14)
    }
    Pour empêcher la RVO, il y a l'option -fno-elide-constructors (ou sous forme d'attribut) dans clang et gcc, mais je ne sais pas s'il existe un équivalent sur msvc. Sinon, on peut caster en référence constante...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Foo f(const Foo& foo1)
    {
        return static_cast<Foo const&>(Foo(foo1.m_num + 1));
    }

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 18/08/2006, 10h34
  2. Comment définir un tableau dans une classe?
    Par Pragmateek dans le forum Collection et Stream
    Réponses: 11
    Dernier message: 30/04/2006, 20h34
  3. Réponses: 8
    Dernier message: 04/04/2006, 17h29
  4. Comment forcer le format d'une cellule?
    Par cha_cha dans le forum Macros et VBA Excel
    Réponses: 5
    Dernier message: 18/11/2005, 14h31
  5. Réponses: 14
    Dernier message: 15/01/2004, 01h15

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