[debutant] Passage d'objet par reference

17 réponses
Avatar
Olivier BURELLI
Bonjour,


J'effectue mon apprentissage du C++ avec le livre suivant de J.
Liberty : le Langage C++

je suis interrogatif concernant le listing en fin de post.

si je comprends bien ce que j'ai appris jusqu'ici :

-dans la d=C3=A9claration de la classe SimpleChat et sa methode, on constru=
it
une copie de l'objet par reference (alias) :
SimpleChat(SimpleChat&) , SimpleChat::SimpleChat(SimpleChat&)

dans la declaration et la methode de FonctionDeux on fait appel a des
pointeurs sur les objets :

SimpleChat* FonctionDeux (SimpleChat *leChat) on dereference bien le
pointeur par l'adresse de l'objet indique dans l'appel de la fonction :
FonctionDeux(Frisky&)

si je comprends bien :

FonctionUn renvoie par valeur la reference de l'objet pour la
construction de sa copie.

FonctionDeux renvoie le parametre par dereferencement du pointeur.

Question : Pourquoi dans le commentaire du listing ci-dessous pour
FonctionDeux est-il est pr=C3=A9cis=C3=A9 par reference ?

Question : Dans l'exposition de mon probl=C3=A8me, ai-je bien assimil=C3=A9=
la
notion de pointeur et reference ? J'ai l'impression que ce n'est pas
clair... Si je m'embrouille un retour et mise en garde serait fort
sympatique.

Si quelqu'un veut bien m'apporter ses lumi=C3=A8res, je lui en serai gr=C3=
=A9e :)

Cdt,

Zolive.


[code]
//listing910.cpp - Passage de pointeur sur des objets

#include <iostream>

using namespace std;
class SimpleChat
{
public:
SimpleChat(); //
constructeur SimpleChat(SimpleChat&); //
constructeur de copie
~SimpleChat(); // destructeur };

SimpleChat::SimpleChat()
{
cout << "Constructeur de SimpleChat.." << endl;
}

SimpleChat::SimpleChat(SimpleChat&)
{
cout << "Constructeur de copie de SimpleChat..." << endl;
}

SimpleChat::~SimpleChat()
{
cout << "Destructeur de SimpleChat..." << endl;
}

SimpleChat FonctionUn (SimpleChat leChat);
SimpleChat* FonctionDeux (SimpleChat *leChat);

int main()
{
cout << "Creation d'un objet Chat..." << endl;
SimpleChat Frisky;
cout << "Appel de FonctionUn..." << endl;
FonctionUn(Frisky);
cout << "Appel de FonctionDeux..." << endl;
FonctionDeux(&Frisky);
return 0;
}

// FonctionUn, passage par valeur
SimpleChat FonctionUn(SimpleChat leChat)
{
cout << "Retour de FonctionUn..." << endl;
return leChat;
}

// FonctionDeux, passage par reference
SimpleChat* FonctionDeux(SimpleChat *leChat)
{
cout << "Retour de FonctionDeux..." << endl;
return leChat;
}
[/code]

10 réponses

1 2
Avatar
espie
In article ,
Olivier BURELLI wrote:
si je comprends bien :

FonctionUn renvoie par valeur la reference de l'objet pour la
construction de sa copie.


Plus que ca: le parametre est passe par valeur, et renvoye par valeur,
donc il y a au moins deux copies.

Ta fonction fait:
A f(A a)
^ ^^^ 1 copie
- 2e copie
{
return a;
}

f(a);
(meme si l'appel ne s'en sert pas).

FonctionDeux renvoie le parametre par dereferencement du pointeur.

Question : Pourquoi dans le commentaire du listing ci-dessous pour
FonctionDeux est-il est précisé par reference ?


C'est clairement une erreur de commentaire.

Question : Dans l'exposition de mon problème, ai-je bien assimilé la
notion de pointeur et reference ? J'ai l'impression que ce n'est pas
clair... Si je m'embrouille un retour et mise en garde serait fort
sympatique.



Si le code suivant est extrait du bouquin sur lequel tu apprends, change
de bouquins: ces exemples me semblent fortement confusogenes.

Ca me parait assez idiot de montrer des exemples qui font ET du passage
de parametres par valeur, ET du retour de parametre par valeur, surtout sans
utiliser la valeur de retour ! ca fait plein de concepts d'un coup.


Normalement n C++ on peut passer un certain temps sans croiser de pointeurs,
ceux-ci commencent a etre necessaires bien plus tard qu'en C.

Faudrait que tu nous dises ce qu'il y a dans ton bouquin sur le passage
par valeur et par reference. Si l'auteur attaque directement avec une
classe, un constructeur de copie, et des pointeurs, ca ne me surprend pas
outre mesure que tu sois perdu.

Pour plus te repondre, faudra sans doute des questions et des exemples
plus simples, qui ne melangent pas plein de concepts d'un coup.
Avatar
Fabien LE LEZ
On Mon, 6 Jun 2011 22:21:40 +0000 (UTC), (Marc Espie):

Si le code suivant est extrait du bouquin sur lequel tu apprends, change
de bouquins: ces exemples me semblent fortement confusogenes.



Effectivement, c'est le merdier.

À ma connaissance, le seul bouquin valable pour enseigner le C++ aux
débutants est Accelerated C++, de Koenig & Moo.

Si l'auteur attaque directement avec une
classe, un constructeur de copie, et des pointeurs, ca ne me surprend pas
outre mesure que tu sois perdu.



D'autant que ça ne servira pas avant un moment. Dans la plupart des
cas (surtout au début), quand on est tenté d'utiliser un constructeur
de copie, c'est qu'on fait beaucoup trop compliqué, ou bien qu'un
réinvente la roue (typiquement, on reprogramme à la main un pointeur
intelligent).
Avatar
Olivier BURELLI
Bonsoir M Espie, content de te croiser ici :)

Je suis assez satisfait de ce livre (le 3eme), bien qu'il y ait
quelques coquilles dans les codes suite à la traduction. Finalement
j'arrive à les corriger.



Faudrait que tu nous dises ce qu'il y a dans ton bouquin sur le
passage par valeur et par reference. Si l'auteur attaque directement
avec une classe, un constructeur de copie, et des pointeurs, ca ne me
surprend pas outre mesure que tu sois perdu.



pour être concis :

Le chapitre en question, References :
-nature et role des references,
-differences entre reference et pointeurs
-creation et utilisation des references, passage par réference de
valeurs et d'objets a des fonctions et recuperation des valeurs
renvoyees

je cite :
dans le chapitre precedent on apprends a gerer des objets sur le tas a
s'y referer de facon indirecte. Ce chapitre presente quasiment les
memes fonctionalités des pointeurs mais avec une syntaxe plus simple.

Le passage par valeur d'un objet a une fonction implique une copie de
cet objet. Lorsque la fonction appelée renvoie un objet, une autre
copie a lieu

ces objets etant stockes dans la pile ces operations prennent du temps
et consommme de la memoire, ces couts sont negligeables pour les petits
objets comme les entiers.

En revanche il ne le sont plus pour les gros objets. La taille de cet
objet correspondant a la somme de toutes les variables membre qui la
composent.

l'auteur expose la problématique des classe, en abordant succinctement
le constructeur de copie qui sera aborde au chapitre suivant. le
theoreme "constructeur de copie" etant ; celui -ci est appele a chaque
fois qu'une copie temporaire de l'objet est place sur la pile.

Lorsque cet objet temporaire est detruit a la fin de l'execution de la
fonction, son destructeur est appelé. Si la fonction renvoie un objet
par valeur, il faut egalement faire copie de cet objet et le detruire.

Avec des objets volumineux ces appels de constructeurs et destructeurs
peuvent avoir un impact sur la vitesse d execution du programme et son
utilisation de la memoire.

pour illustrer cela l'auteur presentait le listing impliqué, le but
montrer la frequence des appels du constructeur / destructeur de copie.

Pour plus te repondre, faudra sans doute des questions et des exemples
plus simples, qui ne melangent pas plein de concepts d'un coup.



C'est le 11 eme code démonstratif du chapitre, c'est le commentaire qui
ne collait pas avec ce que j'essayais de comprendre, d'où ma question.
Je n'osais pas rejeter la faute sur l'auteur ni le traducteur quand
même :p

La seconde, me permettait par retour de lecture du post, de savoir
si je me faisais comprendre, donc avais bien assimilé ce dont j
exposais.

l'objectif est atteint, je retourne à ma forge... je le reprendrais
apres avoir aborde les constructeurs de copie au chapitre suivant.

Merci pour tes lumieres :)
Avatar
espie
In article ,
Olivier BURELLI wrote:
l'auteur expose la problématique des classe, en abordant succinctement
le constructeur de copie qui sera aborde au chapitre suivant. le
theoreme "constructeur de copie" etant ; celui -ci est appele a chaque
fois qu'une copie temporaire de l'objet est place sur la pile.

Lorsque cet objet temporaire est detruit a la fin de l'execution de la
fonction, son destructeur est appelé. Si la fonction renvoie un objet
par valeur, il faut egalement faire copie de cet objet et le detruire.

Avec des objets volumineux ces appels de constructeurs et destructeurs
peuvent avoir un impact sur la vitesse d execution du programme et son
utilisation de la memoire.



Oui, encore que le compilo a le droit d'optimiser des copies, et heureusement
encore.

Deux trois points vraiment importants sur le sujet:
- on differencie en premier approche les objets C++ en "classes concretes":
ce sont des petits objets (point dans le plan, date) qui vont avoir une
semantique de valeur. On ne se prive pas pour en placer directement sur la
pile, ou pour en passer directement aux fonctions. Le reste, ce sont les gros
objets, souvent concus pour l'heritage, et ceux-la seront passes par reference
et possedent souvent leur implementation 'des 4' fonctions: constructeur
par defaut, constructeur de copie, operateur d'affectation, et destructeur.
Dans beaucoup de cas modernes, on delegue: les smart-pointer de boost
permettent par exemple de ne rien avoir a implementer de tout ca, et juste
composer les champs necessaires.
- pour beaucoup d'objets, on va donc privilegier le passage de parametres
par reference. Il est alors vital d'etre "const-correct" (bien annoter tous
les parametres qui doivent etre const d'un const), d'abord, parce que ca
documente la fonction et que ca evite les erreurs stupides (ben oui, un
passage par reference, ca permet de faire des effets de bord ignobles), mais
aussi, parce que les temporaires ne peuvent etre passes que par parametres
const, e.g., f(A(5)) ne fonctionnera que si f(const A&) et pas f(A&).

- un cas ou les references ne sont pas appropries, c'est lorsqu'au final
il faut vraiment creer, un nouveau objet, le classique etant operator+,
par exemple, qui aura souvent comme implementation (je laisse de cote
les techniques d'expression-value a la Veldhuizen):

A operator+(const A& a, const A& b)
{
A c(a);
c += b;
return c;
}

Pas le choix, faut construire l'objet, et donc faire la copie. Mais un
compilo bien foutu disposera de "return value optimisation", et donc construira
c directement en place pour eviter une copie.


Mes petits camarades completeront...
Avatar
Olivier BURELLI
On Tue, 07 Jun 2011 03:26:05 +0200
Fabien LE LEZ wrote:

On Mon, 6 Jun 2011 22:21:40 +0000 (UTC), (Marc Espie):

>Si le code suivant est extrait du bouquin sur lequel tu apprends,
>change de bouquins: ces exemples me semblent fortement confusogenes.

Effectivement, c'est le merdier.

À ma connaissance, le seul bouquin valable pour enseigner le C++ aux
débutants est Accelerated C++, de Koenig & Moo.

>Si l'auteur attaque directement avec une
>classe, un constructeur de copie, et des pointeurs, ca ne me
>surprend pas outre mesure que tu sois perdu.

D'autant que ça ne servira pas avant un moment. Dans la plupart des
cas (surtout au début), quand on est tenté d'utiliser un constructeur
de copie, c'est qu'on fait beaucoup trop compliqué, ou bien qu'un
réinvente la roue (typiquement, on reprogramme à la main un pointeur
intelligent).




Je comprends, néanmoins je trouve que ce livre me convient assez. Les
Classes ont fait l'objet d'un chapitre, les pointeurs aussi, le
constructeur de copie est abordé dans le chapitre suivant.

ce code est le 10 eme de ce chapitre sur les références l'auteur
souhaitait présenter la frequence des appels du constructeur de copie
et sa lourdeur inhérente pour la gestion de memoire. Le but apparement
est de faire prendre conscience au lecteur de l'efficacité du passage de
paramètre par référence.

Actuellement, je garde le rythme du livre. Une fois lu en
entier où lors de mes besoins d'assimilation, je n'hésiterai pas à
effectuer des retours arrière.

Après il faudra que je forge, pour essayer de devenir un programmeur :)

Merci pour ces commentaires.
Avatar
espie
In article ,
Olivier BURELLI wrote:
le trois quart des choses exprimées est abstrait pour moi :) je tag
précieusement ce post pour, un jour ou cela devient comprehensible je
le retrouve. L'héritage et le polymorphysme ne sont abordé
respectivement que dans 3 et 5 chapitres.

J'en ai compris le principe, cela ressemble a la fin de mon chapitre...



Bon, ben j'ai encore plus envie de te dire de jeter ton bouquin aux orties.
Les exemples te montrent un constructeur de copie, te parlent de passage
par reference, alors qu'ils n'ont pas aborde les points dont je parle
(specifiquement, les 4 methodes qui vont ensemble). Et ca parle de pointeur.

Desole, mais ca ressemble fort a un bouquin de C++ ecrit par quelqu'un qui
a fait beaucoup de C et qui ne pense pas en C++.

Un vrai bon bouquin de C++ ne va pas presenter les choses dans le meme
ordre.
Avatar
Olivier BURELLI
On Tue, 7 Jun 2011 09:06:11 +0000 (UTC)
(Marc Espie) wrote:

In article ,
Olivier BURELLI wrote:
>l'auteur expose la problématique des classe, en abordant
>succinctement le constructeur de copie qui sera aborde au chapitre
>suivant. le theoreme "constructeur de copie" etant ; celui -ci est
>appele a chaque fois qu'une copie temporaire de l'objet est place
>sur la pile.
>
>Lorsque cet objet temporaire est detruit a la fin de l'execution de
>la fonction, son destructeur est appelé. Si la fonction renvoie un
>objet par valeur, il faut egalement faire copie de cet objet et le
>detruire.
>
>Avec des objets volumineux ces appels de constructeurs et
>destructeurs peuvent avoir un impact sur la vitesse d execution du
>programme et son utilisation de la memoire.

Oui, encore que le compilo a le droit d'optimiser des copies, et
heureusement encore.

Deux trois points vraiment importants sur le sujet:
- on differencie en premier approche les objets C++ en "classes
concretes": ce sont des petits objets (point dans le plan, date) qui
vont avoir une semantique de valeur. On ne se prive pas pour en
placer directement sur la pile, ou pour en passer directement aux
fonctions. Le reste, ce sont les gros objets, souvent concus pour
l'heritage, et ceux-la seront passes par reference et possedent
souvent leur implementation 'des 4' fonctions: constructeur par
defaut, constructeur de copie, operateur d'affectation, et
destructeur. Dans beaucoup de cas modernes, on delegue: les
smart-pointer de boost permettent par exemple de ne rien avoir a
implementer de tout ca, et juste composer les champs necessaires.
- pour beaucoup d'objets, on va donc privilegier le passage de
parametres par reference. Il est alors vital d'etre
"const-correct" (bien annoter tous les parametres qui doivent etre
const d'un const), d'abord, parce que ca documente la fonction et que
ca evite les erreurs stupides (ben oui, un passage par reference, ca
permet de faire des effets de bord ignobles), mais aussi, parce que
les temporaires ne peuvent etre passes que par parametres const,
e.g., f(A(5)) ne fonctionnera que si f(const A&) et pas f(A&).

- un cas ou les references ne sont pas appropries, c'est lorsqu'au
final il faut vraiment creer, un nouveau objet, le classique etant
operator+, par exemple, qui aura souvent comme implementation (je
laisse de cote les techniques d'expression-value a la Veldhuizen):

A operator+(const A& a, const A& b)
{
A c(a);
c += b;
return c;
}

Pas le choix, faut construire l'objet, et donc faire la copie. Mais
un compilo bien foutu disposera de "return value optimisation", et
donc construira c directement en place pour eviter une copie.


Mes petits camarades completeront...



Ouhh la la,

le trois quart des choses exprimées est abstrait pour moi :) je tag
précieusement ce post pour, un jour ou cela devient comprehensible je
le retrouve. L'héritage et le polymorphysme ne sont abordé
respectivement que dans 3 et 5 chapitres.

J'en ai compris le principe, cela ressemble a la fin de mon chapitre...

Mon problème de départ n'était que le commentaire. Merci pou r tous ces
eclaircissements :)
Avatar
Pascal J. Bourguignon
Olivier BURELLI writes:

J'ai un projet personnel, écrire un programme de gestion de finance
personnelle, j'ai choisi QT que je devrai aussi étudier. A ce sujet il
faudra que je post sur fr.comp.os.bsd sur l'absence de la lib
debug sur QtCreator une foi bien compris le pb.

Challenge un peu gros, souhaitant m'appuyer sur une base postgresql. Le
pb n'étant pas là, j'ai de bonne connaissance en SQL et en architecture
de SGBDR.

La programmation reste pour moi un loisir, je prends le temps qu'il
faut.



À moins que tu aies une raison particulière pour apprendre le C++, ce
n'est pas le choix de langage que j'aurais fait pour écrire un logiciel
de finance personnelle.

Si le but c'est ça, il vaudrait mieux choisir un langage qui met moins
de batons dans les roues.

Par exemple, Common Lisp. (Je comprendrais aussi que l'on choisisse
Python ou Ruby, mais Common Lisp est meilleur).


Par exemple, à l'université de Bordeaux, les étudiants travaillent sur
un projet de comptabilité en Common Lisp:

git clone http://dept-info.labri.fr/~strandh/Compta
http://dept-info.labri.fr/~idurand/enseignement/PP3/pp.pdf


http://cliki.net/ pour plus d'informations.
http://cliki.net/Performance

--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.
Avatar
Fabien LE LEZ
On Tue, 07 Jun 2011 14:19:15 +0200, "Pascal J. Bourguignon"
:

Common Lisp



Tiens, y'avait longtemps.
Avatar
espie
In article ,
Olivier BURELLI wrote:
On Tue, 7 Jun 2011 10:35:15 +0000 (UTC)
(Marc Espie) wrote:

In article ,
Olivier BURELLI wrote:
>le trois quart des choses exprimées est abstrait pour moi :) je tag
>précieusement ce post pour, un jour ou cela devient comprehensible je
>le retrouve. L'héritage et le polymorphysme ne sont abordé
>respectivement que dans 3 et 5 chapitres.
>
>J'en ai compris le principe, cela ressemble a la fin de mon
>chapitre...

Bon, ben j'ai encore plus envie de te dire de jeter ton bouquin aux
orties. Les exemples te montrent un constructeur de copie, te parlent
de passage par reference, alors qu'ils n'ont pas aborde les points
dont je parle (specifiquement, les 4 methodes qui vont ensemble). Et
ca parle de pointeur.

Desole, mais ca ressemble fort a un bouquin de C++ ecrit par
quelqu'un qui a fait beaucoup de C et qui ne pense pas en C++.

Un vrai bon bouquin de C++ ne va pas presenter les choses dans le meme
ordre.



Je l'avais justement achete car ce livre était plébiscité pour son
approche C++ pur. Il n'y ait effectivement fait aucune allusion a
une syntaxique ou une approche du C.

Je comprends l'argumentation, je suis l'élève dans ce cas de figure ne
peux remettre en question le jugement du professeur (mon livre).
Néanmoins, si tu peux me conseiller un livre je suis preneur, toi qui
enseigne si je ne me trompe pas.



Je ne connais pas cet ouvrage, il est possible qu'il y ait un biais dans
ton approche. On t'a deja conseille "accelerated C++" qui est a mon avis
egalement un excellent bouquin d'apprentissage du C++.
1 2