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 avec le constructeur de copie quand mon paramètre n'est pas un const


Sujet :

Langage C++

  1. #1
    Membre régulier
    Homme Profil pro
    Développeur .NET/C/C++
    Inscrit en
    Septembre 2007
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET/C/C++
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2007
    Messages : 71
    Points : 122
    Points
    122
    Par défaut Problème avec le constructeur de copie quand mon paramètre n'est pas un const
    Bonjour à tous,
    voilà, dans mon code, j'ai une classe dont j'ai surchargé le constructeur de copie. Le truc, c'est que mon constructeur reçoit en paramètre une reference non constante car il doit modifier l'objet d'origine.
    Voici un code simplifier histoire d'illustrer cela :
    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
    37
    38
    39
    40
    41
     
    #include <iostream>
     
    template <typename T>
    struct floating_ptr
    {
    	T* value;
    	floating_ptr(T* const pointer) : value(pointer)
    	{}
    	floating_ptr(floating_ptr& other) : value(other.release())
    	{}
    	T* release()
    	{
    		T* res = value;
    		value = NULL;
    		return res;
    	}
    	T& operator*()
    	{
    		return *value;
    	}
    	floating_ptr& operator=(floating_ptr& other)
    	{
    		value = other.release();
    		return *this;
    	}
    };
     
    floating_ptr<int> allocate_int(int value)
    {
    	floating_ptr<int> res(new int(value));
    	return res;
    }
     
    int main(int argc, char** argv)
    {
    	floating_ptr<int> p_argc = allocate_int(argc);
    	std::cout << "Number of parameters : " << *p_argc;
     
    	return 0;
    }
    Maintenant, si j'essaie de compiler, cela me donne ceci :
    g++ -c pointer.cpp
    pointer.cpp: In function ‘int main(int, char**)’:
    pointer.cpp:36:46: error: no matching function for call to ‘floating_ptr<int>::floating_ptr(floating_ptr<int>)’
    pointer.cpp:36:46: note: candidates are:
    pointer.cpp:9:2: note: floating_ptr<T>::floating_ptr(floating_ptr<T>&) [with T = int, floating_ptr<T> = floating_ptr<int>]
    pointer.cpp:9:2: note: no known conversion for argument 1 from ‘floating_ptr<int>’ to ‘floating_ptr<int>&’
    pointer.cpp:7:2: note: floating_ptr<T>::floating_ptr(T*) [with T = int]
    pointer.cpp:7:2: note: no known conversion for argument 1 from ‘floating_ptr<int>’ to ‘int*’
    Quelqu'un a une idée d'ou vient le problème?
    Pour info, j'ai essayé de comparer ma classe avec la classe auto_ptr, mais je ne parvient pas à voir ce qui cloche dans mon code.

  2. #2
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    L'expression :
    Est une r-value, et le compilateur n peux pas appeler le constructeur de copie définie ainsi car le compilateur devrait initialisé une référence non constante (le paramètre de ton constructeur de copie) avec une r-value, chose qu'il ne peut pas faire. Avec un référence constante il pourrait.

    Tu as vraiment besoin que le paramètre soit non constante, parce que même si c'est bel et bien un constructeur de copie, sémantiquement c'est assez déroutant que faire une copie modifie l'objet d'origine. Si les modifications que l'objet à copié doit subir sont de l'ordre technique et n'ont pas de lien avec le sens de la classe, alors tu pourrais utiliser mutable.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    struct A
    {
      mutable int i;
      A(const A& a) : i(++(a.i))
      { }
    };
    Sinon, si tu en as la possibilité, tu peux utiliser les rref du C++2011 et définir un "move-ctor" :
    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
     
    struct A
    {
      int i;
      A() =default;
      A(A&& a) : i(++(a.i))
      { }
    };
     
    A foo()
    { return A(); }
     
    int main()
    {
      A a = foo();
      return 0;
    }

  3. #3
    Membre régulier
    Homme Profil pro
    Développeur .NET/C/C++
    Inscrit en
    Septembre 2007
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET/C/C++
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2007
    Messages : 71
    Points : 122
    Points
    122
    Par défaut
    Merci pour l'explication. Cependant un truc m'échappe: comment se fait-il que le compilateur ne puisse instancier une reference non constante sur base d'une r-value? Y'a-t-il une raison à cela?

    Sinon, en regardant plus en détail le code des auto_ptr, je suis tombé sur ceci :
    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
     
    /** 
           *  @brief  Automatic conversions
           *
           *  These operations convert an %auto_ptr into and from an auto_ptr_ref
           *  automatically as needed.  This allows constructs such as
           *  @code
           *    auto_ptr<Derived>  func_returning_auto_ptr(.....);
           *    ...
           *    auto_ptr<Base> ptr = func_returning_auto_ptr(.....);
           *  @endcode
           */
          auto_ptr(auto_ptr_ref<element_type> __ref) throw()
          : _M_ptr(__ref._M_ptr) { }
     
          auto_ptr&
          operator=(auto_ptr_ref<element_type> __ref) throw()
          {
    	if (__ref._M_ptr != this->get())
    	  {
    	    delete _M_ptr;
    	    _M_ptr = __ref._M_ptr;
    	  }
    	return *this;
          }
     
          template<typename _Tp1>
            operator auto_ptr_ref<_Tp1>() throw()
            { return auto_ptr_ref<_Tp1>(this->release()); }
     
          template<typename _Tp1>
            operator auto_ptr<_Tp1>() throw()
            { return auto_ptr<_Tp1>(this->release()); }
     
    /* Je vous passe ici la definition des auto_ptr_ref, laquelle est assez simple en fait */
    Apparement, c'est ce bout de code qui permet aux auto_ptr de fonctionner dans ce cas de figure. En effet, la r-value est en fait casté en un auto_ptr_ref, et on utilise ensuite le constructeur qui reçoit un auto_ptr_ref en paramètre et non le constructeur de copie (enfin si jai bien compris)
    Je vais donc essayer de faire de même dans mon code.
    Pour le coup du move-constructor, je compte l'utiliser à terme, mais pour le moment j'aimerai déjà pouvoir faire fonctionner cela sans faire appel aux nouveautés de la prochaine norme.

  4. #4
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Pour la raison, je ne peux pas t'assurer que ma réponse soit correct, mais je pense que l'idée est qu'une référence est un alias sur quelque-chose qui existe déjà, et que typiquement une r-value c'est quelque chose qui ne va pas exister longtemps et que donc il serait illogique de pouvoir travailler dessus (dans le sens la modifier), alors que si elle est constante on ne fait que "regarder" ce qui ne semble pas incohérent.

    Et sinon oui c'est bien ce mécanisme qui est utilise, en épurant c'est ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    struct B
    {
      struct A {};
      B() =default;
      B(B&){}
      B(A){}
      operator A(){return A();}
    };

  5. #5
    Membre régulier
    Homme Profil pro
    Développeur .NET/C/C++
    Inscrit en
    Septembre 2007
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET/C/C++
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2007
    Messages : 71
    Points : 122
    Points
    122
    Par défaut
    Juste pour ceux que ça intéresse, le fait d'avoir une classe intermédiaire et de surcharger les operateurs de casting permet bien de résoudre ce problème.

    petit extrait de mon code :
    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
     
    /* ... */
    template<typename T>
    struct floating_ptr_rvalue
    {
        T* value;
        inline floating_ptr_rvalue(T* data) : value(data) {}
        inline floating_ptr_rvalue& operator=(T* const data) { value = data; }
        inline T* get() const { return value; } 
    };
     
    /* ... */
     
    template <typename T>
    class floating_ptr
    {
     
        floating_ptr(const floating_ptr_rvalue<value_type>& data) : value(data.value)
        {}
     
        /* ... */
        inline floating_ptr& operator=(const floating_ptr_rvalue<T>& data)
        {
            value = data.get();
            return *this;
        }
     
        template<typename U>
        inline operator floating_ptr_rvalue<U>()
        { 
            floating_ptr_rvalue<U> res(value);
            value = NULL;
            return res;
        }

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

Discussions similaires

  1. Exécuter un cron job quand mon pc n'est pas allumé
    Par Ismatus1 dans le forum Linux
    Réponses: 7
    Dernier message: 11/11/2011, 18h04
  2. problème avec le constructeur de copie
    Par ikuzar dans le forum Débuter
    Réponses: 14
    Dernier message: 02/02/2011, 17h26
  3. Quand mon site n'est pas chargé depuis le HTML
    Par Gregi dans le forum Intégration
    Réponses: 0
    Dernier message: 02/01/2010, 22h43
  4. Petit problème avec le constructeur par copie
    Par beegees dans le forum C++
    Réponses: 16
    Dernier message: 01/04/2008, 16h34
  5. [Debutant] Problème avec un constructeur par copie
    Par Drannor dans le forum Débuter
    Réponses: 5
    Dernier message: 12/03/2007, 09h15

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