Подтвердить что ты не робот

Передать по ссылке/значению в С++

Я хотел бы уточнить различия между значением и ссылкой.

Я нарисовал изображение

enter image description here

Итак, для передачи по значению

копия идентичного объекта создается с другой ссылкой, а локальной переменной присваивается новая ссылка, поэтому указывать на новую копию

Как понимать слова: " Если функция изменяет это значение, модификации появятся также в рамках функции вызова для передачи как по значению, так и по ссылке "

Спасибо!

4b9b3361

Ответ 1

Я думаю, что большая путаница возникает из-за того, что не сообщается, что подразумевается под передачей по ссылке. Когда некоторые люди говорят, что они передаются по ссылке, они обычно означают не сам аргумент, а объект, на который ссылаются. Некоторые другие говорят, что передача по ссылке означает, что объект не может быть изменен в вызываемом. Пример:

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
}

Некоторые люди утверждают, что 1 и 3 проходят по ссылке, а 2 - по стоимости. Другая группа людей говорит, что все, кроме последнего, проходят по ссылке, потому что сам объект не копируется.

Я хотел бы сделать определение того, что здесь, как я утверждаю, проходит по ссылке. Общий обзор по нему можно найти здесь: Разница между передачей по ссылке и переходом по значению. Первый и последний проходят по значению, а средние два проходят по ссылке:

    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.

Я голосую за следующее определение:

Аргумент (1.3.1) передается по ссылке тогда и только тогда, когда соответствующий параметр вызываемой функции имеет ссылочный тип и ссылочный параметр напрямую связывается с выражением аргумента (8.5.3/4). Во всех остальных случаях мы имеем дело с переходом по значению.

Это означает, что следующее значение передается по значению:

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 - это пропуск по значению, поскольку он не связан напрямую. Реализация может скопировать временную и затем привязать ее к ссылке. 2 передается по значению, потому что реализация инициализирует временный литерал, а затем привязывается к ссылке. 3 передается по значению, поскольку параметр не имеет ссылочного типа. 4 - по значению по той же причине. 5 передается по значению, потому что параметр не имеет ссылочного типа. Следующие случаи проходят по ссылке (по правилам 8.5.3/4 и другие):

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

Ответ 2

При передаче по значению:

void func(Object o);

а затем вызов

func(a);

вы построите Object в стеке, а в рамках реализации func на него будет ссылаться o. Это может быть мелкая копия (внутренние элементы a и o могут указывать на одни и те же данные), поэтому a может быть изменен. Однако если o является глубокой копией a, то a не изменится.

При прохождении по ссылке:

void func2(Object& o);

а затем вызов

func2(a);

вы только дадите новый способ ссылки a. "a" и "o" - это два имени для одного и того же объекта. Изменение o внутри func2 сделает эти изменения видимыми для вызывающего, кто знает объект по имени "a".

Ответ 3

Спасибо всем за все эти данные!

Я привел это предложение из лекции в Интернете: http://www.cs.cornell.edu/courses/cs213/2002fa/lectures/Lecture02/Lecture02.pdf

первая страница 6-го слайда

" Пройдите мимо VALUE Значение переменной передается вместе с функцией Если функция изменяет это значение, модификации остаются в пределах область действия этой функции.

Перейдите по ссылке Ссылка на переменную передается вместе с функцией Если функция изменяет это значение, модификации появятся также в рамках вызывающей функции.

"

Еще раз спасибо!

Ответ 4

Я не уверен, правильно ли понимаю ваш вопрос. Это немного неясно. Однако, что может вас смутить, следующее:

  • При передаче по ссылке к вызываемой функции передается ссылка на тот же объект. Любые изменения объекта будут отражены в исходном объекте, и, следовательно, вызывающий его увидит.

  • При передаче по значению будет вызываться конструктор копирования. Конструктор копии по умолчанию будет выполнять только мелкую копию, следовательно, если вызываемая функция модифицирует целое число в объекте, это не будет видно вызывающей функции, но если функция изменяет структуру данных, на которую указывает указатель внутри объекта, то это будет видно вызывающей стороне из-за мелкой копии.

Возможно, я неправильно понял ваш вопрос, но я думал, что все равно дам ему удар.

Ответ 5

Как я его разбираю, эти слова ошибочны. Он должен читать: "Если функция изменяет это значение, модификации появляются также в области вызывающей функции при передаче по ссылке, но не при передаче по значению".

Ответ 6

Мое понимание слов "Если функция изменяет это значение, модификации появляются также в пределах области вызывающей функции как для передачи по значению, так и по ссылке" заключается в том, что они являются ошибкой.

Изменения в вызываемой функции не в области вызывающей функции при передаче по значению.

Либо вы ошиблись в цитированных словах, либо они были извлечены из любого контекста, сделанного тем, что кажется неправильным, правильно.

Не могли бы вы убедиться, что вы правильно указали свой источник, и если ошибок нет, вы получите больше текста, окружающего этот оператор в исходном материале.