web-dev-qa-db-fra.com

Passer par référence / valeur en C ++

Je voudrais clarifier les différences entre par valeur et par référence.

J'ai dessiné une image

enter image description here

Donc, pour passer par la valeur,

une copie d'un objet identique est créée avec une référence différente, et la variable locale est affectée à la nouvelle référence, afin de pointer vers la nouvelle copie

Comment comprendre les mots: "Si la fonction modifie cette valeur, les modifications apparaissent également dans le cadre de la fonction appelante pour le passage par valeur et par référence"

Merci!

35
user36064

Je pense que beaucoup de confusion est générée en ne communiquant pas ce que l'on entend par passé par référence . Lorsque certaines personnes disent passer par référence , cela signifie généralement non pas l'argument lui-même, mais plutôt l'objet référencé . Certains autres disent que passer par référence signifie que l'objet ne peut pas être modifié dans l'appelé. Exemple:

struct Object {
    int i;
};

void sample(Object* o) { // 1
    o->i++;
}

void sample(Object const& o) { // 2
    // nothing useful here :)
}

void sample(Object & o) { // 3
    o.i++;
}

void sample1(Object o) { // 4
    o.i++;
}

int main() {
    Object obj = { 10 };
    Object const obj_c = { 10 };

    sample(&obj); // calls 1
    sample(obj) // calls 3
    sample(obj_c); // calls 2
    sample1(obj); // calls 4
}

Certaines personnes prétendent que 1 et 3 sont transmis par référence, tandis que 2 correspondent à la valeur. Un autre groupe de personnes dit que tout sauf le dernier est passé par référence, car l'objet lui-même n'est pas copié.

Je voudrais en tirer une définition ici ce que je prétends être passer par référence . Un aperçu général à ce sujet peut être trouvé ici: Différence entre passer par référence et passer par valeur . Le premier et le dernier sont passés par valeur, et les deux intermédiaires sont passés par référence:

    sample(&obj);
       // yields a `Object*`. Passes a *pointer* to the object by value. 
       // The caller can change the pointer (the parameter), but that 
       // won't change the temporary pointer created on the call side (the argument). 

    sample(obj)
       // passes the object by *reference*. It denotes the object itself. The callee
       // has got a reference parameter.

    sample(obj_c);
       // also passes *by reference*. the reference parameter references the
       // same object like the argument expression. 

    sample1(obj);
       // pass by value. The parameter object denotes a different object than the 
       // one passed in.

Je vote pour la définition suivante:

Un argument (1.3.1) est passé par référence si et seulement si le paramètre correspondant de la fonction appelée a un type de référence et le paramètre de référence se lie directement à l'expression d'argument (8.5.3/4). Dans tous les autres cas, il s'agit de passer par valeur.

Cela signifie que ce qui suit est passé par valeur:

void f1(Object const& o);
f1(Object()); // 1

void f2(int const& i);
f2(42); // 2

void f3(Object o);
f3(Object());     // 3
Object o1; f3(o1); // 4

void f4(Object *o);
Object o1; f4(&o1); // 5

1 est passé par valeur, car il n'est pas directement lié. L'implémentation peut copier le temporaire puis le lier à la référence. 2 est passé par valeur, car l'implémentation initialise un temporaire du littéral puis se lie à la référence. 3 est une valeur de passage, car le paramètre n'a pas de type de référence. 4 est passé par valeur pour la même raison. 5 est passé par valeur car le paramètre n'a pas de type de référence. Les cas suivants sont passés par référence (selon les règles de 8.5.3/4 et autres):

void f1(Object *& op);
Object a; Object *op1 = &a; f1(op1); // 1

void f2(Object const& op);
Object b; f2(b); // 2

struct A { };
struct B { operator A&() { static A a; return a; } };
void f3(A &);
B b; f3(b); // passes the static a by reference
61

Lors du passage par valeur:

void func(Object o);

puis appeler

func(a);

vous construirez un Object sur la pile, et dans l'implémentation de func il sera référencé par o. Il peut s'agir d'une copie superficielle (les internes de a et o peuvent pointer vers les mêmes données), donc a peut être modifié. Cependant, si o est une copie complète de a, alors a ne changera pas.

En passant par référence:

void func2(Object& o);

puis appeler

func2(a);

vous ne donnerez qu'une nouvelle façon de référencer a. "a" et "o" sont deux noms pour le même objet. Modification de o à l'intérieur func2 rendra ces modifications visibles à l'appelant, qui connaît l'objet sous le nom "a".

8
Flame

Merci beaucoup à tous pour toutes ces contributions!

J'ai cité cette phrase d'une note de conférence en ligne: http://www.cs.cornell.edu/courses/cs213/2002fa/lectures/Lecture02/Lecture02.pdf

la première page la 6ème diapositive

"Pass by VALUE La valeur d'une variable est transmise à la fonction Si la fonction modifie cette valeur, les modifications restent dans la portée de cette fonction.

Passer par REFERENCE Une référence à la variable est transmise à la fonction Si la fonction modifie cette valeur, les modifications apparaissent également dans le cadre de la fonction appelante.

"

Merci encore!

6
user36064

Je ne sais pas si j'ai bien compris votre question. C'est un peu flou. Cependant, ce qui pourrait vous dérouter est le suivant:

  1. Lors du passage par référence, une référence au même objet est transmise à la fonction appelée. Toutes les modifications apportées à l'objet seront reflétées dans l'objet d'origine et donc l'appelant le verra.

  2. Lors du passage par valeur, le constructeur de copie sera appelé. Le constructeur de copie par défaut ne fera qu'une copie superficielle, par conséquent, si la fonction appelée modifie un entier dans l'objet, cela ne sera pas vu par la fonction appelante, mais si la fonction modifie une structure de données pointée par un pointeur dans l'objet , alors cela sera vu par l'appelant en raison de la copie superficielle.

J'ai peut-être mal compris votre question, mais j'ai pensé que je pourrais lui donner un coup de couteau de toute façon.

5
vboctor

Comme je l'ai analysé, ces mots sont faux. Il doit indiquer "Si la fonction modifie cette valeur, les modifications apparaissent également dans la portée de la fonction appelante lors du passage par référence, mais pas lors du passage par valeur".

2
dreeves

Ma compréhension des mots "Si la fonction modifie cette valeur, les modifications apparaissent également dans le cadre de la fonction appelante pour le passage par valeur et par référence" est qu'elles sont ne erreur.

Les modifications apportées dans une fonction appelée sont pas dans la portée de la fonction appelante lors du passage par valeur.

Soit vous avez mal saisi les mots cités, soit ils ont été extraits de tout contexte qui a fait que ce qui semble être faux, n'est-ce pas?.

Pourriez-vous s'il vous plaît vous assurer d'avoir correctement cité votre source et s'il n'y a pas d'erreurs, donnez plus de texte entourant cette déclaration dans le document source.

1
jwpfox