38 votes

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

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

J'ai dessiné une image

enter image description here

Donc, pour le passage par valeur,

une copie identique d'un objet est créé avec une référence différente, et la variable locale est assigné à la nouvelle référence, de manière à pointer vers la nouvelle copie

Comment comprendre le sens des mots: " Si la fonction modifie la valeur, les modifications apparaissent également dans le cadre de l'appel de la fonction de passage par valeur et par référence "

Merci!

65voto

Je pense que beaucoup de confusion est généré par le fait de ne pas faire ce que l'on entend par passé par référence. Quand certaines personnes disent passage par référence , ils signifient généralement pas l'argument lui-même, mais plutôt l'objet référencé. Certains autres disent que le passage par référence signifie que l'objet ne peut pas être modifié dans le destinataire de 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 le 1 et le 3 sont passer par référence, tandis que 2 serait le passage par valeur. Un autre groupe de gens disent tous, mais le dernier est le passage par référence, parce que l'objet lui-même n'est pas copié.

Je voudrais attirer une définition de ce là ce que je demande à passer par référence. Un aperçu général sur il peut être trouvé ici: Différence entre le passage par référence et le passage par valeur . Tous les mais la première et la dernière sont passage 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 est le type de référence et la valeur de référence se lie directement à l'argument de l'expression (8.5.3/4). Dans tous les autres cas, nous avons à faire avec le passage par valeur.

Cela signifie que suivant est le passage 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 le passage par valeur, car il n'est pas directement lié. La mise en œuvre peut copier le temporaire et le lier ensuite que temporaire à la référence. 2 est le passage par valeur, parce que la mise en œuvre initialise une temporaire de la littéralité et se lie alors à la référence. 3 est le passage par valeur, parce que le paramètre n'a pas de type de référence. 4 est le passage par valeur pour la même raison. 5 est le passage par valeur, parce que le paramètre n'a pas de type de référence. Les cas suivants sont passage par référence (par les règles de 8.5.3/4 et d'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

8voto

Flame Points 1138

Lors du passage par valeur:

void func(Object o);

et puis l'appel de

func(a);

vous allez construire un Objet sur la pile, et sera référencé par l'o. Ce peut être une copie( de l'intérieur de a et o peut-être les mêmes données ), donc a peut-être changé. Cependant est o est une copie en profondeur d'un, alors un ne va pas changer.

Lorsque le passage par référence:

void func(Object& o);

et puis l'appel de

func(a);

vous ne serez en donnant une nouvelle façon de faire référence à un. a et o sont des noms pour le même objet. Changer l'intérieur func fera de ces changements visibles pour l'appelant, qui connaissent l'objet comme une.

6voto

user36064 Points 283

Merci beaucoup à tous pour tous ces commentaires!

J'ai cité cette phrase à partir d'un cours en ligne: http://www.cs.cornell.edu/courses/cs213/2002fa/lectures/Lecture02/Lecture02.pdf

la première page de la 6e diapositive

" Le passage par VALEUR La valeur d'une variable est transmise à la fonction Si la fonction modifie la valeur, les modifications restent au sein de l' la portée de cette fonction.

Passage par RÉFÉRENCE Une référence à la variable est transmise à la fonction Si la fonction modifie la valeur, les modifications apparaissent également dans le cadre de l'appel de la fonction.

"

Merci beaucoup encore une fois!

5voto

vboctor Points 695

Je ne suis pas sûr si je comprends votre question correctement. C'est un peu floues. Cependant, ce qui pourrait être source de confusion vous est la suivante:

  1. Lorsque le passage par référence, une référence au même objet est passé à la fonction appelée. Toute modification de l'objet sera reflétée dans l'objet d'origine et, partant, l'appelant va le voir.

  2. Lors du passage par valeur, le constructeur de copie sera appelée. Le constructeur de copie par défaut ne fera que d'une copie, par conséquent, si la fonction appelée modifie un entier dans l'objet, ce ne sera pas vu par l'appel de la fonction, mais si les changements de la fonction d'une structure de données pointé par un pointeur à l'intérieur de l'objet, puis ce sera vu par l'appelant en raison de la faible copie.

Je pourrais avoir mal compris votre question, mais j'ai pensé que je donnerais un coup de poignard de toute façon.

2voto

dreeves Points 9130

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".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X