besoin de testeurs: retour de fonction

besoin de testeurs: retour de fonction - C++ - Programmation

Marsh Posté le 25-07-2003 à 23:55:01    

Code :
  1. #include <iostream>
  2. using namespace std;
  3. class Foo
  4. {
  5. public:
  6.   Foo()
  7.   {
  8.     cout << "Foo()\t"
  9.  << "this = " << this
  10.  << endl;
  11.   }
  12.   Foo(int i)
  13.   {
  14.     cout << "Foo(int)\t"
  15.  << "this = " << this
  16.  << endl;
  17.   }
  18.   Foo(const Foo &other)
  19.   {
  20.     cout << "Foo(Foo)\t"
  21.  << "this = " << this
  22.  << " other = " << &other
  23.  << endl;
  24.   }
  25.   ~Foo()
  26.   {
  27.     cout << "~Foo()\t"
  28.  << "this = " << this
  29.  << endl;
  30.   }
  31.   Foo& operator=(const Foo &other)
  32.   {
  33.     cout << "opertor=(Foo)\t"
  34.  << "this = " << this
  35.  << " other = " << &other
  36.  << endl;
  37.     return *this;
  38.   }
  39. };
  40. Foo f()
  41. {
  42.   cout << "\nf()\n";
  43.   return Foo();
  44. }
  45. Foo g()
  46. {
  47.   cout << "\ng()\n";
  48.   return Foo(42);
  49. }
  50. Foo h()
  51. {
  52.   cout << "\nh()\n";
  53.   Foo tmp;
  54.   return tmp;
  55. }
  56. int main()
  57. {
  58.   Foo res;
  59.   res=f();
  60.   res=g();
  61.   res=h();
  62. }


 
 
qui donne avec mon compilateur (g++ 3.3.1)
 

Foo()   this = 0xbffffc30
 
f()
Foo()   this = 0xbffffc20
opertor=(Foo)   this = 0xbffffc30 other = 0xbffffc20
~Foo()  this = 0xbffffc20
 
g()
Foo(int)        this = 0xbffffc20
opertor=(Foo)   this = 0xbffffc30 other = 0xbffffc20
~Foo()  this = 0xbffffc20
 
h()
Foo()   this = 0xbffffc20
opertor=(Foo)   this = 0xbffffc30 other = 0xbffffc20
~Foo()  this = 0xbffffc20
~Foo()  this = 0xbffffc30


Message édité par Taz le 25-07-2003 à 23:56:10
Reply

Marsh Posté le 25-07-2003 à 23:55:01   

Reply

Marsh Posté le 25-07-2003 à 23:58:00    

VC7 / Release:

Code :
  1. Foo()   this = 0012FED8
  2. f()
  3. Foo()   this = 0012FED7
  4. opertor=(Foo)   this = 0012FED8 other = 0012FED7
  5. ~Foo()  this = 0012FED7
  6. g()
  7. Foo(int)        this = 0012FED7
  8. opertor=(Foo)   this = 0012FED8 other = 0012FED7
  9. ~Foo()  this = 0012FED7
  10. h()
  11. Foo()   this = 0012FEB0
  12. Foo(Foo)        this = 0012FED7 other = 0012FEB0
  13. ~Foo()  this = 0012FEB0
  14. opertor=(Foo)   this = 0012FED8 other = 0012FED7
  15. ~Foo()  this = 0012FED7
  16. ~Foo()  this = 0012FED8
  17. Press any key to continue


 

Reply

Marsh Posté le 26-07-2003 à 00:01:08    

fait une recopie en trop je regardes les options d'optimisation...

Reply

Marsh Posté le 26-07-2003 à 00:01:54    

ouais y a un truc bizarre... voir ce topic http://forum.hardware.fr/forum2.ph [...] h=&subcat=
et les différentes traces...


Message édité par Taz le 26-07-2003 à 00:03:18
Reply

Marsh Posté le 26-07-2003 à 00:16:52    

j'obtiens la meme trace que toi, c'est à dire pour h si je remplace
 
return tmp;
 
par  
 
return Foo(tmp);
 
 
je me renseigne sur ce comportement...
 
c'est interessant...

Reply

Marsh Posté le 26-07-2003 à 00:35:06    

je viens de faire un test avec openwatcom:
 

Code :
  1. loading object files
  2. searching libraries
  3. creating a PMODE/W executable
  4. C:\Temp\rtetrert>t
  5. Foo()   this = 0x1cef8
  6. f()
  7. Foo()   this = 0x1cef4
  8. opertor=(Foo)   this = 0x1cef8 other = 0x1cef4
  9. ~Foo()  this = 0x1cef4
  10. g()
  11. Foo(int)        this = 0x1cef0
  12. opertor=(Foo)   this = 0x1cef8 other = 0x1cef0
  13. ~Foo()  this = 0x1cef0
  14. h()
  15. Foo()   this = 0x1ceec
  16. opertor=(Foo)   this = 0x1cef8 other = 0x1ceec
  17. ~Foo()  this = 0x1ceec
  18. ~Foo()  this = 0x1cef8

Reply

Marsh Posté le 26-07-2003 à 00:41:49    

VC6 a le même comportement que VC7 (il y a une recopie de trop)

Reply

Marsh Posté le 26-07-2003 à 00:44:17    

BJOne a écrit :

VC6 a le même comportement que VC7 (il y a une recopie de trop)

le tout est de savoir si c'est vraiment en trop. comme tu peux voir dans l'autre topic, c'est très pénalisant  :ouch:

Reply

Marsh Posté le 26-07-2003 à 00:47:23    

bin ça casse un peu le truc à la base :/

Reply

Marsh Posté le 26-07-2003 à 00:47:41    

j'ai pas borland c++ 6 d'installé :/

Reply

Marsh Posté le 26-07-2003 à 00:47:41   

Reply

Marsh Posté le 26-07-2003 à 00:49:03    

BJOne a écrit :

bin ça casse un peu le truc à la base :/

oui, et même pour une expression simple, ça fait un boulot considérable en plus!

Reply

Marsh Posté le 26-07-2003 à 10:40:58    

la réponse de Jean Marc Bourget sur fclc++
Je suis d'accord avec lui, il s'agit d'une optimisation permise par la norme
 
 

Citation :

> je me pose des questions sur les retours de fonction et les copies
 
Il y a deux choses à considérer: le comportement logique et les
optimisations permises par la norme.
 
Le comportement logique c'est que le retour de fonction utilise le
constructeur de copie.
 
Les optimisations permises sont au nombres de deux:
 
   - en toute circonstance (donc pas uniquement au retour d'une
     fonction), quand un constructeur de copie devrait être appelé
     pour copier un temporaire, le compilateur peut utiliser le
     temporaire à la place (ou plus vraissemblablement contruire
     directement le temporaire)
 
   - lorsqu'on retourne un objet nommé d'une fonction, on peut
     utiliser l'objet plutôt que d'en faire une copie (NRVO) (ou plus
     vraissemblablement mettre l'objet nommé directement à l'endroit
     ou la valeur de retour de la fonction est attendu, donc même si
     la norme le permet, je doute qu'un compilateur utilise la NRVO
     quand dans des chemins différents on retourne des objets nommés
     différents sauf dans des cas particuliers -- voir ci-dessus)
 
> Foo f()
> {
>   cout << "\nf()\n";
>   return Foo();
> }
 
On retourne un temporaire:  
  construction du temporaire
  construction de la valeur retournée par copie du temporaire
    (peut être supprimée en construisant le temporaire directement en
     tant que valeur retournée)
donc 0 ou 1 copie
 
> Foo g()
> {
>   cout << "\ng()\n";
>   return Foo(42);
> }
 
Même chose
 
> Foo h()
> {
>   cout << "\nh()\n";
>   Foo tmp;
>   return tmp;
> }
 
On retourne une valeur nommée:
   construction de la valuer
   construction de la valeur retournée par copie de la valeur nommée
    (peut être supprimée en construisant la valeur nommée directement en
     tant que valeur retournée)
donc 0 ou 1 copie
 
> Foo i()
> {
>   cout << "\nh()\n";
>   Foo tmp;
>   return Foo(tmp);
> }
 
On retourne un temporaire construit à partir d'une valeur nommée.
   construction de la valeur nommée
   construction du temporaire par copie de la valeur nommée
   construction de la valeur retournée par copie du temporaire
    (peut être supprimée en construisant le temporaire directement en
     tant que valeur retournée)
donc 1 ou 2 copies
 
 
> donne sur mon systeme (linux, g++ 3.3.1)
 
On voit que g++ implémente les deux optimisations
 
> avec VC7, la trace de h() donne
>  
>  h()
>   Foo()   this = 0012FEB0
>   Foo(Foo)        this = 0012FED7 other = 0012FEB0 ~Foo()  this = 0012FEB0
>   opertor=(Foo)   this = 0012FED8 other = 0012FED7 ~Foo()  this = 0012FED7
>   ~Foo()  this = 0012FED8
 
et que VC7 n'a pas le NRVO
 
A propos de ma remarque sur les objets différents, dans ce cas
 
Foo nrvo(bool b) {
  if (b) {
    Foo res1;
    return res1;
  } else {
    Foo res2;
    return res2;
  }
}
 
rien n'empèche l'application du nrvo (on retourne des objets
différents mais il n'y a pas de problème de destruction car l'autre
objet ne doit pas être détruit), pourtant ni gcc 3.3 ni como ne le
font pas alors qu'ils le font pour
 
Foo nrvo(bool b) {
  Foo res1;
  if (b) {
    return res1;
  } else {
    return res1;
  }
}

Reply

Marsh Posté le 15-09-2003 à 15:14:11    

Sinon je viens de tester avec VS.NET 2003, le constructeur de recopie en trop y est aussi, avec le compilo Intel C++ 7 c'est bon.

Reply

Marsh Posté le 15-09-2003 à 15:29:20    

BJOne a écrit :

j'ai pas borland c++ 6 d'installé :/


 
moi je l'ai :
 


Foo()   this = 1245060
 
f()
Foo()   this = 1245052
opertor=(Foo)   this = 1245060 other = 1245052
~Foo()  this = 1245052
 
g()
Foo(int)        this = 1245044
opertor=(Foo)   this = 1245060 other = 1245044
~Foo()  this = 1245044
 
h()
Foo()   this = 1244968
Foo(Foo)        this = 1245036 other = 1244968
~Foo()  this = 1244968
opertor=(Foo)   this = 1245060 other = 1245036
~Foo()  this = 1245036
~Foo()  this = 1245060


Message édité par antp le 15-09-2003 à 15:30:12

---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 15-09-2003 à 15:30:05    

Le comportement est appelé "return value optimization" et il y a déjà pas mal de discussions sur le sujet ici. L'article le plus complet sur le sujet (et qui relève les contradictions à ce sujet dans l'ARM !) est celui-ci.
 
Le problème est de savoir si le compilateur peut effectivement se passer de la recopie. Pour cela il faut qu'aucun constructeur n'ait d'effet de bord.
 
Par exemple :

Code :
  1. class Foo
  2. {
  3. public:
  4. Foo() { ++numInstances_; }
  5. Foo( const Foo& f ) { ++numInstances_; }
  6. private:
  7. static int numInstances_;
  8. };
  9. int Foo::numInstances_ = 0;
  10. Foo f()
  11. {
  12. Foo f;
  13. /* ... */
  14. return f;
  15. }


 
Ici, il est nécessaire de ne pas faire l'optimisation. En effet, il y a réellement la création d'un objet Foo et ensuite sa recopie. Or à cause de la variable statique, l'appel aux deux constructeurs est obligatoire.
Par contre, si la variable statique numInstances_ n'existait pas, l'optimisation serait justifiée.


Message édité par gatorette le 15-09-2003 à 15:33:18

---------------
each day I don't die is cheating
Reply

Marsh Posté le 15-09-2003 à 16:30:13    

(ceux qui ont un compilo optimisant pourrait essayer avec l'exemple de gatorette ?)

Reply

Marsh Posté le 15-09-2003 à 16:38:32    

je teste comment ? faut mélanger les deux codes source ? (pas envie de chercher là, je veux un truc à copier/coller :D)


---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 15-09-2003 à 16:41:44    

toi tu test rien ton borland optimise pas :O
 
(bon si t'as, tu balance le code de gatorette et tu regardes la valeur de la variable statique apres execution, ou tu rajoute un cout<<"kookoo" dans le constructeur)

Reply

Marsh Posté le 15-09-2003 à 16:44:51    

[Linker Error] Unresolved external '_main' referenced from D:\BORLAND\CBUILDER6\LIB\C0X32.OBJ
 
:o


---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 15-09-2003 à 16:46:26    

Code :
  1. int main()
  2. {
  3. Foo f = f();
  4. }


beta :O

Reply

Marsh Posté le 15-09-2003 à 16:56:48    

numInstances vaut 2
et ton Foo f = f(); il aime pas, vu que f est pas une fonction mais un Foo :D


Message édité par antp le 15-09-2003 à 16:58:25

---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 15-09-2003 à 16:58:26    

la y'a kooye dans gigot [:ddr555]
 
ah ok c reglé :O


Message édité par chrisbk le 15-09-2003 à 16:58:49
Reply

Marsh Posté le 15-09-2003 à 16:58:38    

j'ai édité, j'avais mal corrigé ton code :o


---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 15-09-2003 à 17:19:55    

ça va ?

Reply

Marsh Posté le 15-09-2003 à 17:30:14    

oui, et toi ? :)
(:heink:)


---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 15-09-2003 à 17:31:03    

ché pas, c'est quoi ces manières de upper au bout de 25 jours?  :)


Message édité par Taz le 15-09-2003 à 17:31:33
Reply

Marsh Posté le 15-09-2003 à 17:42:20    

c'est pas moi qui ai uppé :o


---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 15-09-2003 à 18:03:16    

tiens j'avais meme pas fait gaffe qu'il avait 15ans ce topic

Reply

Marsh Posté le 15-09-2003 à 18:16:53    

Je n'avais pas vu non plus qu'il datait tant ce topic.
 

Taz a écrit :

la réponse de Jean Marc Bourget sur fclc++
- en toute circonstance (donc pas uniquement au retour d'une fonction), quand un constructeur de copie devrait être appelé pour copier un temporaire, le compilateur peut utiliser le temporaire à la place (ou plus vraissemblablement contruire directement le temporaire)
- lorsqu'on retourne un objet nommé d'une fonction, on peut utiliser l'objet plutôt que d'en faire une copie (NRVO) (ou plus vraissemblablement mettre l'objet nommé directement à l'endroit ou la valeur de retour de la fonction est attendu, donc même si la norme le permet, je doute qu'un compilateur utilise la NRVO quand dans des chemins différents on retourne des objets nommés différents sauf dans des cas particuliers -- voir ci-dessus)


Je pense que ces affirmations ne prennent pas en compte le cas que j'ai exposé au-dessus. En effet, si le constructeur ou le destructeur ont des effets de bord, il n'est pas possible de faire l'optimisation.


---------------
each day I don't die is cheating
Reply

Marsh Posté le 15-09-2003 à 18:36:29    

:heink:
 
 
et dans tous les cas ce détail est laissé libre à l'implémentation. donc il n'y a aucun de problème, sauf pour les conceptions et codes de mauvaises factures


Message édité par Taz le 15-09-2003 à 18:42:46
Reply

Marsh Posté le 15-09-2003 à 18:43:34    

Ben dans mon sujet au-dessus, je présente un cas où un compilateur qui ferait tout le temps l'optimisation ferait une erreur. En effet, en cas d'optimisation, numInstances_ vaudrait 1 alors qu'il doit faire 2.


---------------
each day I don't die is cheating
Reply

Marsh Posté le 15-09-2003 à 18:46:24    

mais c'est pas une otpimisation !
la norme dit "on peut faire une copie inutile ou pas"
 
 
et pi je peux te dire le contraire num vaut 2 au lieu de 1


Message édité par Taz le 15-09-2003 à 18:46:53
Reply

Marsh Posté le 15-09-2003 à 19:04:11    

Bon, j'admets m'être misérablement planté...  [:befree]
En relisant en entier l'article que je cite au-dessus, je me suis rendu compte qu'en fait en juillet 1996 le comité ANSI/ISO s'était réuni et autorisait l'élimination de la copie inutile (d'après les conditions énumérées dans DWP
12.8
- c'est quoi ça ?).


---------------
each day I don't die is cheating
Reply

Marsh Posté le 15-09-2003 à 19:08:28    

Draft Working Paper

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed