Salut,
D'abord, il semble intéressant de s'assurer que tu aies bien compris la différence entre le fait de passer un ojet par valeur et celui de passer un objet par référence.
Quand tu crées des fonctions dont le prototype est
1 2 3 4 5 6 7 8 9 10
|
void FonctionVal(type obj);
/* ou */
void FonctionRef(type& obj);
/* qui seraient utilisées sous une forme proche de */
type mavar;
FonctionVal(mavar);
/*ou */
FonctionRef(mavar); |
FonctionVal va travailler avec une
copie de mavar, alors que FonctionRef va travailler avec mavar
lui-meme.
Du coup, si dans FonctionVal, tu modifie obj, mavar n'est pas modifiée une fois que la fonction a été appelée. Par contre, si tu modifie obj dans FonctionRef, les modification apportées seront répercutées sur mavar.
Et c'est là que réside le principal effet de bord.
On parle plus volontiers d' "
effet de bord" que d' "
effet secondaires" parce qu'un effet secondaire a cette connotation de "effet indésiré", alors qu'un effet de bord indique qu'il s'agit d'un comportement tout à fait cohérent avec la définition que l'on donne d'un terme, mais auquel on ne pensera pas forcément... avant de s'etre fait avoir
Ceci étant dit, l'implémentation de ce que j'ai expliqué plus haut sous la forme de
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
| #include <iostream>
using namespace std;
struct type
{
int x;
int y;
};
void FonctionVal(type obj)
{
obj.x+=2;
obj.y*=2;
cout<<"2- Dans FonctionVal:"<<endl
<<" obj.x = "<<obj.x<<" obj.y = "<<obj.y<<endl<<endl;
}
void FonctionRef(type& obj)
{
obj.x*=2;
obj.y+=2;
cout<<"4- Dans FonctionRef:"<<endl
<<" obj.x = "<<obj.x<<" obj.y = "<<obj.y<<endl<<endl;
}
int main()
{
type mavar={10,10};
cout<<"1- A la creation :"<<endl
<<" mavar.x = "<<mavar.x<<" mavar.y = "<<mavar.y<<endl<<endl;
FonctionVal(mavar);
cout<<"3- Apres FonctionVal"<<endl
<<" mavar.x = "<<mavar.x<<" mavar.y = "<<mavar.y<<endl<<endl;
FonctionRef(mavar);
cout<<"5- Apres FonctionRef:"<<endl
<<" mavar.x = "<<mavar.x<<" mavar.y = "<<mavar.y<<endl<<endl;
return 0;
} |
dont le code compile et fournit la sortie
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
1- A la creation:
mavar.x = 10 mavar.y = 10
2- Dans FonctionVal:
obj.x = 12 obj.y = 20
3- Apres FonctionVal:
mavar.x = 10 mavar.y = 10
4- Dans FonctionRef:
obj.x = 20 obj.y = 12
5- Apres FonctionRef
mavar.x = 20 mavar.y = 12 |
te montre ( en 4 et en 5) que mavar est bel et bien modifié quand elle est passée à FonctionRef.
L'une des solution est, donc, effectivement, de passer un objet qui ne doit pas etre modifié par la fonction par valeur plutot que par référence.
Cependant, car rien n'est jamais simple en informatique, le passage d'argument par valeur peut avoir, lui aussi, des conséquences dramatiques - ne serait-ce que au niveau des performances sur les objets importants - parce qu'il implique la copie intégrale de l'objet.
C'est la raison pour laquelle on préférera souvent utiliser le mot cle
const et le passage d'argument par référence pour les gros objets.
Ce mot clé indique simplement au compilateur que
Le compilateur étant alors au courent de ton engagement ne se genera pas pour t' "insulter" si tu essaye malgré tout de modifier l'objet dans la fonction.
C'est ce que l'on appelle, en anglais une construction "
const-correct" (correcte du point de vue de la constance)
Le problème est encore plus subtil pour ce qui concerne les retours de fonctions.
Quelque chose à laquelle on ne pense pas (forcément), c'est, par exemple, le fait qu'une variable locale est détruite une fois que l'on sort de la portée (pour faire simple le couple d'accolades) dans laquelle elle est déclarée.
Ainsi, un code du genre
1 2 3 4 5 6 7 8 9 10
|
typeperso& MaFonction()
{
typeperso ret;
/* toute la gestion du type perso */
return ret;
/* Attention!!! ret est detruit lorsque l'accolade fermante est atteinte */
}
/* appelée sous la forme de */
typeperso mavar=MaFonction(); |
aurait l'effet de bord (parce qu'il correspond au comportement inhérent à la définition de "portée") que mavar va correspondre à une variable... qui n'existe plus, et dont la mémoire est susceptible d'etre réutilisée pour autre chose
Partager