Problème de conversion implicite (c++) avec Visual .Net 2003

Bonjour, 

J’ai un petit probleme avec visual .net 2003 avec une classe possédant une conversion implicite et un operateur de copie ayant comme argument une référence (non const)

le code est le suivant:

class CObject { public: CObject(a = 0) {_a=a;}

CObject(CObject&obj)
{ *this = obj;
}

CObject& operator=(CObject&obj) //fct 1
{  _a = obj.a;
}

void operator=(int a)  //fct 2
 {  _a = a;
}

operator int() //fct 3
{  return _a;
}

int _a;
};

CObject getObj()
{  return CObject(10);
}

void main()
{  CObject a;
a = getObj();
}


lors de l’affectation a = getObj();,
au lieu de faire appel à l’operateur de copie 1 il fait appel a la fonction 3 puis a
la fonction 2.

Si on change le prototype de la fonction 1 en (const CObject&obj) ou en (CObject obj)
il appele bien l’operateur de copie 1

Si qq1 c’est si c’est normal ou un bug…

Ce message a été édité par Nithril le 03/12/2003

bon deja : y a pas de qq1 ici y a des gens, voir de temps en temps, quelqu’un… mais pas de qq1

sinon : Ton copy constructeur (fonction 1), il doit porter le const : tu ne modifies pas l’etats de l’object copie : donc const roXor (et en plus ca aide le compilo a generer du meilleurs code, meme que…)… et je pense que c’est ca qui le fait partir en vrille, la seul solution, qui garantie de ne pas changer a, c’est de le caster en int (fonction 3) puis d’utiliser l’affectation en int (fonction 2)…

Donc solution a ton probleme : ton operateur de copie doit etre :

CObject& operator=(const CObject&obj)[/quote]et voilaaa [img]style_emoticons/<#EMO_DIR#>/smile.gif[/img]

J’appele ca une rustine, pas une solution, quand tu veux faire Paris Marseille, tu passe pas par Moscou.
D’ailleur un compilateur ne doit pas partir en vrille (sinon on a pas fini), personnellement j’appele ca un bug ou un nom respect de la norme, et alors la on est mal barré…

Compilo je connais pas, je connais que des compilateurs .

[quote]J’appele ca une rustine, pas une solution, quand tu veux faire Paris Marseille, tu passe pas par Moscou.
D’ailleur un compilateur ne doit pas partir en vrille (sinon on a pas fini), personnellement j’appele ca un bug ou un nom respect de la norme, et alors la on est mal barré…

Compilo je connais pas, je connais que des compilateurs .[/quote]Ha ben il a bon dos le compilo, on pige pas ce qu’on ecrit et c’est direct un non respect de la norme ou un bug… Non, en fait, c’est logique. Il faut casse l’ambiguite sinon le compilo il fait ce qu’il sait faire, le truc le plus generique qui cadre avec ce que tu lui demande. Et deux choses si tu veux poster ici :

  1. sois un peu moins agressif stp, tu piges pas comment marche un compilo, et qu’il faut casser les ambiguite quand on veut qu’il fasse ce qu’on veut, c’est pas la faute a Count0…
  2. fais des phrases en francais. “Si qq1 c’est si c’est normal ou un bug”==”Quelqu’un sait si c’est normal ou un bug” c’est n’importe quoi…

Quand deux objets ont meme type, et que tu fais une affectation et que l’operateur existe, je vois pas ou est l’ambiguité

Pour tes 2 points:

  • Je suis en rien aggressif, contrairement a toi, tu aurais pu me répondre que c’est tous a fait normal explication a l’appui, mais non tu me critiques
  • Les fautes ca peut arriver, celui qui n’en a jamais fait qu’il me jete la 1ere pierre…

[méchanceté_gratuite] je te lance la première pierre ! [/méchanceté_gratuite]

Bon sinon, euh, je viens de vérifier tes allégations douteuses cher ami Nithril. Et quelle ne fut pas ma suprise quand j’ai vu que… ben chez moi ton code (corrigé hein, parce que bon il compile pas tel quel) fonctionne comme tu t’attends à ce qu’il fonctionne.

Voici le code exact tel que je l’ai utilisé :

class CObject { public:   CObject(int a = 0) {_a=a;}   CObject(CObject&obj)   {   *this = obj;   }

  CObject& operator=(CObject &obj) //fct 1
  {
  _a = obj._a;
    return *this;
  }

  void operator=(int a) //fct 2
  {
  _a = a;
  }

  operator int() //fct 3
  {
  return _a;
  }

  int _a;
};

CObject GetObj()
{
  return CObject(10);
}

Et voila le code assembleur généré par Visual Studio .NET 2002 (en Debug, parce que bon, en Release ce brave Visual me le remplace grosso modo par un "mov eax, 0x0A"... ce qui est tout a fait ce que fait le code au dessus, au final ) :
  CObject a; //<-- Déclaraction de A, bon ça appelle le 0042562E push 0 // constructeur avec 0, logique jusque la. 00425630 lea ecx,[a] 00425633 call CObject::CObject (4255F0h)   a = GetObj();   //<-- Appel à la fonction GetObj() (ben oui) 00425638 lea eax,[ebp-8E4h] 0042563E push eax 0042563F call GetObj (4255D0h) 00425644 add esp,4   00425647 push eax   <-- On récupére la valeur de retour, 00425648 lea ecx,[a] pushée sur la pile, "&a" dans ecx 0042564B call CObject::operator= (426300h)    Et enfin, appel de l'opérateur "=".
(Petite note au passage : pour ceux qui savent pas, en C++ "this" est un "paramètre caché" des méthodes non statiques d'un objet.)

Bref, tout ça pour dire que je m’étonne que tu ai le problème en fait. Soit mon compilo a trop bu, soit euh ben c’est moi qui ait trop bu. Mais ça c’est pas possible, je le saurais.

Et pour finir tiens : je jette une pierre à GloP avant que notre c0unt0 local ne l’égore pour avoir écrit « Count0 » au lieu de « c0unt0 » :wink: Et aussi pour avoir écrit « stp » tiens. Que vient faire la Société des Transports Poitevins dans un thread sur le code, je n’ai toujours pas compris.

(oui bon, la on pourrait croire que je cherche les emmerdes, donc je précise : JE RIGOOOOLEUH ! PATAPER !)

[EDIT] pour reformater mon texte parce que bon entre ce qu’on prévisu et ce qu’il y a au final y’a une légère différence, qui fait toute la différence justement

Ce message a été édité par tuo le 04/12/2003

Ce probleme est issu d’une migration de code de Visual C++ 6 à .Net 2003.

Une personne a tester avec gcc (mais je ne sais pas quelle version) et ca donne le
meme resultat qu’avec .Net 2003 : passage par la conversion implicite et affectation.

donc Visu 6 et Visu 2002 passe direct par l’affectation
mais gcc (version x) et Visu 2003 passe avant par la conversion implicite

bref, bug ou respect de la norme?

Je précise que le const dans l’affectation n’est pas possible car l’argument droit de l’operateur est modifié (non je ne ferais pas un static_cast )

donc Visu 6 et Visu 2002 passe direct par l’affectation mais gcc (version x) et Visu 2003 passe avant par la conversion implicite
bref, bug ou respect de la norme?
Bah : a different ““compilateurs”” different resultats, ca me semble normal, surtout en c++ (je ne m’ettendrais pas sur le sujet : c’est pas bon pour ma tension ) par contre pourquoi il fait ca comme ca : aucune idee… mais ca laisse reveur… faudrait que j’essaye avec code warrior… pour rire…
Je précise que le const dans l’affectation n’est pas possible car l’argument droit de l’operateur est modifié (non je ne ferais pas un static_cast )
Pardon ? tu modifies la source de ta copie ?
alors tu prends ton fusil, et puis ton grand couteau, tu trouve le gars genial qu’a designe ca : et tu lui fait coup de l’ours (d’abords le fusil, puis le couteau, puis tu vends le reste ) En tout cas : j’espere que c’est super super super pas possible de faire autrement : parce que c’est vraiment vraiment vraiment sal…

C’est lourd quand meme, surtout quand il s’agit d’une difference aussi insidueuse.

Je precise aussi que ce probleme ne me concerne pas directement. C’est dans
l’entreprise où je suis ils sont passé a .Net. En compilant un projet fonctionnant
parfaitement sous Visual 6, sous .Net 2003 ils ont rencontré ce petit soucis.

[quote]Pardon ? tu modifies la source de ta copie ?
alors tu prends ton fusil, et puis ton grand couteau, tu trouve le gars genial qu’a designe ca : et tu lui fait coup de l’ours (d’abords le fusil, puis le couteau, puis tu vends le reste
En faite, il s’agit d’un auto pointeur, lors d’une affectation le contenu de l’auto pointeur de l’operande de droite ne doit plus etre valide car le contenu d’un auto pointeur ne doit pas etre partagé.

heu, c’est quoi un auto-pointeur ? c’est un smart pointer qui parle francais ?

P.S : bienvenu dans le monde du “j’ai un code, 32 compilATEURS() et ca marche pas pareil partout”… l’histoire de ma vie
Ce message a été édité par c0unt0 le 04/12/2003

Je connaissais pas non plus avant, c’est un smart pointeur donc le contenu n’est pas partageable.

genre si je fais ca:

AutoPrt a(ptr);
AutoPrt b = a;

a ne dois plus etre utilisé et  a._ptr doit etre mis a nul, d’ou l’absence de const dans
l’operateur d’affectation

Bon, je viens de tester dans VS.NET 2003 par curiosité et en effet, il passe par les « int » le voyou. Mettre « const » corrige le problème mais du coup ce n’est plus le fonctionnement que tu attends. Sinon, virer les méthodes de conversion en « int » fait que le code compilé utilise l’opérateur « = ». Mais bon, je suppose que tu les utilise ces opérateurs :wink:

Bref, c’est la joie, le bonheur. Et comme le dit c0unt0, quand t’as 250 plateformes à gérer avec 450 compilateurs, c’est la galère quotidienne ça

Tiens, je n’avais pas vu ce thread. Je vais tenter une explication du comportement mais n’hésitez pas à me corriger si vous considérez que je dis une ânerie (je pense qu’il n’était pas nécessaire de le préciser )

La définition de l’opérateur de copie ‘=’ est :

T & T::operator=(const T &

Si le compilo ne trouve pas cette définition il va utliser l’opérateur standard de copie, c.a.d. la copie de membre à membre (l’opérateur par défaut). Le membre unique étant de type int, hop conversion implicite. L’opérateur de conversion étant surchargé, zou appelle de fct2.

C’est assez simple et semble respecter la définition du langage.
Petit bémol tout de même, la définition d’un opérateur de copie ne semble pas être obligatoirement telle que je l’ai mentionné. Le compilo g++ V2.95 accèpte la méthode suivante :

void T::operator=(const T & { member1 = T.member1 ;   member2 = T.member2 ; }

D’ailleurs ça m’amène à une question : quelle est l’intérêt de retourner *this ? cf. définition classique de cet opérateur :

T & T::operator=(const T & { member1 = T.member1 ;   member2 = T.member2 ;   return( *this ) ; }

[/quote]Ce message a été édité par Moktar le 05/12/2003

[quote]D’ailleurs ça m’amène à une question : quelle est l’intérêt de retourner *this ? cf. définition classique de cet opérateur :

T & T::operator=(const T & { member1 = T.member1 ;   member2 = T.member2 ;   return( *this ) ; }
Ah ! ca je peux répondre !

retourner *this permet tout simplement de donner une valeur au couple a=b, permettre ainsi de faire :
c = a = b .

Défini comme void , a = b renverra rien, le compilo ne saura pas qu’affecter à c.

De la même manière, tu dois pouvoir écrire :
c = a+= b // c prends la nouvelle valeur de a

et donc

T & T::operator+=(const T & _v ) { member1 += _v.member1 ;   member2 += _v.member2 ;   return( *this ) ; }
[/quote]

[quote]D’ailleurs ça m’amène à une question : quelle est l’intérêt de retourner *this ?[/quote]Bon je dis peut-être une connerie mais moi il me semble que la « valeur » en tant qu’expression d’une affectation est généralement la valeur affectée. Ca permet d’affecter une valeur et de faire un test sur celle-ci en une ligne de code, comme par exemple:

if (a = :wink:
{ /* etc */ }

Bon évidemment on peut faire la même chose en deux étapes (a = b; if (:stuck_out_tongue: etc), mais c’est un bon moyen de rendre ton code un peu plus confus…  

EDIT: bon ben j’ai été trop lent pour répondre (cfr post de Tzim), en plus pour donner une réponse pas complète… Pfff je retourne me coucher moi… 
Ce message a été édité par Kenny209 le 05/12/2003

[quote]

[quote]

D’ailleurs ça m’amène à une question : quelle est l’intérêt de retourner *this ? cf. définition classique de cet opérateur :

T & T::operator=(const T &[img]style_emoticons/<#EMO_DIR#>/wink.gif[/img]