Какая разница между передачей по ссылке или передачей по значению?

В чем разница между

  • параметр, переданный по ссылке
  • параметр, переданный значением?

Не могли бы вы привести несколько примеров?

+469
источник поделиться
19 ответов

Прежде всего, различие "передача по стоимости и передача по ссылке", как это определено в теории CS, теперь устарело, потому что техника, первоначально определенная как "передача по ссылке", с тех пор перестала пользоваться популярностью и в настоящее время редко используется. 1

Более новые языки 2, как правило, используют другую (но схожую) пару методов для достижения тех же результатов (см. Ниже), что является основным источником путаницы.

Вторым источником путаницы является тот факт, что в "передаче по ссылке" "ссылка" имеет более узкое значение, чем общий термин "ссылка" (потому что фраза предшествует этому).


Теперь, подлинное определение:

  • Когда параметр передается по ссылке, вызывающая сторона и вызываемая сторона используют одну и ту же переменную для параметра. Если вызываемый объект изменяет переменную параметра, эффект виден переменной вызывающей стороны.

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

Что следует отметить в этом определении:

  • "Переменная" здесь означает саму переменную вызывающего (локальную или глобальную) - то есть, если я передам локальную переменную по ссылке и присвоу ей, я изменю саму переменную вызывающего, а не, например, то, на что она указывает, если это указатель,

    • Сейчас это считается плохой практикой (как неявная зависимость). Таким образом, практически все новые языки являются исключительно или почти исключительно передаваемыми по значению. Передача по ссылке теперь в основном используется в форме "аргументов вывода/ввода" в языках, где функция не может возвращать более одного значения.
  • Значение "ссылка" в "передать по ссылке". Разница с общим термином "ссылка" заключается в том, что эта "ссылка" является временной и неявной. В сущности, вызываемый объект получает "переменную", которая как-то "совпадает" с исходной. То, как конкретно достигается этот эффект, не имеет значения (например, язык может также раскрывать некоторые детали реализации - адреса, указатели, разыменование - все это не имеет значения; если конечный эффект таков, то это передача по ссылке).


Теперь в современных языках переменные имеют тенденцию быть "ссылочными типами" (другая концепция, изобретенная позже, чем "передача по ссылке" и вдохновленная ими), то есть фактические данные объекта хранятся где-то отдельно (обычно в куче), и только "ссылки" на него когда-либо хранятся в переменных и передаются как параметры. 3

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

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

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

Для них нет согласованного имени, что приводит к искаженным объяснениям, таким как "вызов по значению, где значение является ссылкой". В 1975 году Барбара Лисков предложила термин " обмен вызовами по объектам " (или иногда просто "обмен вызовами по обмену"), хотя он так и не получил широкого распространения. Более того, ни одна из этих фраз не проводит параллели с оригинальной парой. Неудивительно, что старые термины в конечном итоге использовались в отсутствие чего-то лучшего, что приводило к путанице. 4


ПРИМЕЧАНИЕ. В течение длительного времени этот ответ гласил:

Скажем, я хочу поделиться с вами веб-страницей. Если я скажу вам URL, я передаю по ссылке. Вы можете использовать этот URL, чтобы увидеть ту же веб-страницу, которую я вижу. Если эта страница изменилась, мы оба увидим изменения. Если вы удаляете URL-адрес, все, что вы делаете - это уничтожаете ссылку на эту страницу - вы не удаляете саму страницу.

Если я распечатаю страницу и дам вам распечатку, я передаю по значению. Ваша страница является отключенной копией оригинала. Никаких последующих изменений вы не увидите, а внесенные вами изменения (например, пометки на распечатке) не будут отображаться на исходной странице. Если вы уничтожили распечатку, вы фактически уничтожили свою копию объекта - но исходная веб-страница осталась нетронутой.

Это в основном правильно, за исключением более узкого значения "ссылка" - оно является как временным, так и неявным (это не обязательно, но явное и/или постоянное является дополнительными функциями, а не частью семантики передачи по ссылке)., как объяснено выше). Более близкая аналогия - дать вам копию документа и пригласить вас поработать над оригиналом.


1Если вы не программируете на Fortran или Visual Basic, это не стандартное поведение, и в большинстве современных языков использование истинного вызова по ссылке даже невозможно.

2Изрядное количество старших тоже поддерживают это

3В нескольких современных языках все типы являются ссылочными типами.Этот подход был впервые введен языком CLU в 1975 году и с тех пор был принят многими другими языками, включая Python и Ruby.И во многих других языках используется гибридный подход, где некоторые типы являются "типами значений", а другие - "ссылочными типами" - среди них С#, Java и JavaScript.

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

+976
источник

Это способ передачи аргументов в функции. Передача по ссылке означает, что параметр вызываемых функций будет таким же, как переданный аргумент вызывающих (а не значение, а идентификатор - сама переменная). Передача по значению означает, что параметр вызываемых функций будет копией переданного аргумента вызывающих. Значение будет одинаковым, но идентификатор - переменная - отличается. Таким образом, изменение параметра, выполняемого вызываемой функцией в одном случае, изменяет переданный аргумент, а в другом случае просто изменяет значение параметра в вызываемой функции (которая является только копией). Быстро спешите:

  • Java поддерживает только передачу по значению. Всегда копирует аргументы, даже если при копировании ссылки на объект параметр вызываемой функции указывает на тот же объект, и изменения в этом объекте будут отображаться в вызывающем. Поскольку это может ввести в заблуждение, здесь - это то, о чем говорит Джон Скит об этом.
  • С# поддерживает передачу по значению и передает по ссылке (ключевое слово ref, используемое при вызове и вызываемой функции). У Jon Skeet также есть хорошее объяснение этого здесь.
  • С++ поддерживает передачу по значению и передает по ссылке (тип ссылочного параметра, используемый в вызываемой функции). Ниже вы найдете объяснение этого.

Коды

Поскольку мой язык - С++, я буду использовать это здесь

// passes a pointer (called reference in java) to an integer
void call_by_value(int *p) { // :1
    p = NULL;
}

// passes an integer
void call_by_value(int p) { // :2
    p = 42;
}

// passes an integer by reference
void call_by_reference(int & p) { // :3
    p = 42;
}

// this is the java style of passing references. NULL is called "null" there.
void call_by_value_special(int *p) { // :4
    *p = 10; // changes what p points to ("what p references" in java)
    // only changes the value of the parameter, but *not* of 
    // the argument passed by the caller. thus it pass-by-value:
    p = NULL;
}

int main() {
    int value = 10;
    int * pointer = &value;

    call_by_value(pointer); // :1
    assert(pointer == &value); // pointer was copied

    call_by_value(value); // :2
    assert(value == 10); // value was copied

    call_by_reference(value); // :3
    assert(value == 42); // value was passed by reference

    call_by_value_special(pointer); // :4
    // pointer was copied but what pointer references was changed.
    assert(value == 10 && pointer == &value);
}

И пример в Java не повредит:

class Example {
    int value = 0;

    // similar to :4 case in the c++ example
    static void accept_reference(Example e) { // :1
        e.value++; // will change the referenced object
        e = null; // will only change the parameter
    }

    // similar to the :2 case in the c++ example
    static void accept_primitive(int v) { // :2
        v++; // will only change the parameter
    }        

    public static void main(String... args) {
        int value = 0;
        Example ref = new Example(); // reference

        // note what we pass is the reference, not the object. we can't 
        // pass objects. The reference is copied (pass-by-value).
        accept_reference(ref); // :1
        assert ref != null && ref.value == 1;

        // the primitive int variable is copied
        accept_primitive(value); // :2
        assert value == 0;
    }
}

Википедия

http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_value

http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_reference

Этот парень довольно много гвонит:

http://javadude.com/articles/passbyvalue.htm

+124
источник
другие ответы

Связанные вопросы


Похожие вопросы

Многие ответы здесь (и, в частности, самый высокий ответ) фактически неверны, поскольку они неправильно понимают, что означает "вызов по ссылке". Здесь я попытался решить проблему.

TL; DR

Проще говоря:

  • вызов по значению означает, что вы передаете значения как аргументы функции
  • вызов по ссылке означает, что вы передаете переменные в качестве аргументов функции

В метафорических выражениях:

  • Вызов по значению, где я записываю что-то на листе бумаги и передаю его вам. Возможно, это URL, может быть, это полная копия "Войны и мира". Независимо от того, что это такое, это на листе бумаги, который я вам дал, и теперь это действительно ваш лист бумаги. Теперь вы можете писать на этом листе бумаги или использовать этот лист бумаги, чтобы найти что-то в другом месте и поиграть с ним, что бы это ни было.
  • Вызов по ссылке - это когда я даю вам свою записную книжку, в которой записано что-то в ней. Вы можете писать в моей записной книжке (может быть, я хочу, чтобы вы это сделали, может быть, я этого не сделаю), а потом я держу свою тетрадь с любыми каракулями, которые вы там положили. Кроме того, если то, что либо вы, либо я написал, есть информация о том, как найти что-то в другом месте, либо вы, либо я могу пойти туда и поиграть с этой информацией.

Что "вызов по значению" и "вызов по ссылке" не означает

Обратите внимание, что обе эти концепции полностью независимы и ортогональны из понятия ссылочных типов (которые в Java - это все типы, которые являются подтипами Object, а в С# все class типы), или понятие типов указателей, как в C (которые семантически эквивалентны "ссылочным типам" Java, просто с различным синтаксисом).

Понятие ссылочного типа соответствует URL-адресу: оно само является частью информации, и это ссылка (указатель, если хотите) на другую информацию. Вы можете иметь много копий URL-адреса в разных местах, и они не изменяют, на каком веб-сайте они все ссылаются; если веб-сайт обновляется, то каждая копия URL-адреса все равно приведет к обновленной информации. И наоборот, изменение URL-адреса в любом месте не повлияет на любую другую письменную копию URL-адреса.

Обратите внимание, что С++ имеет понятие "ссылки" (например, int&), которое не, как типы ссылок Java и С#, но -, как "вызов по ссылке". Java и С# "ссылочные типы" и все типы в Python похожи на то, что C и С++ вызывают "типы указателей" (например, int*).


ОК, здесь более длинное и более формальное объяснение.

Терминология

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

Чтобы начать, вот пример на некотором C-подобном языке объявления функции:

void foo(int param) {  // line 1
  param += 1;
}

И вот пример вызова этой функции:

void bar() {
  int arg = 1;  // line 2
  foo(arg);     // line 3
}

Используя этот пример, я хочу определить некоторые важные биты терминологии:

  • foo - это функция, объявленная в строке 1 (Java настаивает на том, чтобы делать все функции, но концепция одинакова без потери общности; C и С++ делают различие между декларацией и определением, которые я не буду вдаваться в здесь)
  • param является формальным параметром foo, также объявленным в строке 1
  • arg - это переменная, в частности локальная переменная функции bar, объявленная и инициализируемая в строке 2
  • arg также является аргументом для конкретного вызова foo в строке 3

Здесь есть два очень важных набора понятий. Первая - это значение по сравнению с переменной:

  • Значение - это результат оценки выражения на языке. Например, в функции bar выше, после строки int arg = 1; выражение arg имеет значение 1.
  • Переменная - это контейнер для значений. Переменная может быть изменчивой (это по умолчанию используется на большинстве C-подобных языков), только для чтения (например, объявлено с использованием Java final или С# readonly) или глубоко непреложным (например, с использованием С++ const)).

Другая важная пара понятий, которые следует различать, - параметр с аргументом:

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

Вызов по значению

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

Это работает точно так же, как любые другие типы переменных инициализируются значениями. Например:

int arg = 1;
int another_variable = arg;

Здесь arg и another_variable - вполне независимые переменные - их значения могут меняться независимо друг от друга. Однако в точке, где объявлен another_variable, она инициализируется для хранения того же значения, что и arg, которое равно 1.

Поскольку они являются независимыми переменными, изменения в another_variable не влияют на arg:

int arg = 1;
int another_variable = arg;
another_variable = 2;

assert arg == 1; // true
assert another_variable == 2; // true

Это в точности совпадает с отношением между arg и param в нашем примере выше, что я повторю здесь для симметрии:

void foo(int param) {
  param += 1;
}

void bar() {
  int arg = 1;
  foo(arg);
}

Это точно так, как если бы мы написали код таким образом:

// entering function "bar" here
int arg = 1;
// entering function "foo" here
int param = arg;
param += 1;
// exiting function "foo" here
// exiting function "bar" here

То есть определяющей характеристикой того, что вызов по значению означает, является то, что вызываемый (foo в этом случае) получает значения в качестве аргументов, но имеет свои собственные переменные для этих значений из переменных вызывающего (bar в этом случае).

Возвращаясь к моей метафоре выше, если я bar и вы foo, когда я звоню вам, я вручу вам лист бумаги со значением, написанным на нем. Вы называете этот лист бумаги param. Это значение является копией значения, которое я написал в своем ноутбуке (мои локальные переменные), в переменной, которую я вызываю arg.

(В стороне: в зависимости от аппаратного обеспечения и операционной системы существуют различные соглашения о том, как вы вызываете одну функцию из другой. Вызывающее соглашение похоже на то, как мы решаем, записываю ли значение на куске своей бумаги, а затем вручную это вам, или если у вас есть листок бумаги, на котором я его пишу, или если я напишу его на стене перед нами обоими. Это тоже интересный вопрос, но далеко за рамки этого уже длительного ответ.)

Вызов по ссылке

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

Возвращаясь к нашему примеру выше, это эквивалентно:

// entering function "bar" here
int arg = 1;
// entering function "foo" here
// aha! I note that "param" is just another name for "arg"
arg /* param */ += 1;
// exiting function "foo" here
// exiting function "bar" here

Так как param - просто другое имя для arg - то есть они те же переменные, изменения в param отражаются в arg. Это основной способ, в котором вызов по ссылке отличается от вызова по значению.

Очень немногие языки поддерживают вызов по ссылке, но С++ может сделать это следующим образом:

void foo(int& param) {
  param += 1;
}

void bar() {
  int arg = 1;
  foo(arg);
}

В этом случае param имеет не только то же значение, что и arg, но фактически arg (просто другое имя), и поэтому bar может наблюдать что arg был увеличен.

Обратите внимание, что это не, как работает любой из Java, JavaScript, C, Objective-C, Python или почти любого другого популярного языка. Это означает, что эти языки не вызывают по ссылке, они вызывают по значению.

Добавление: вызов по общему ресурсу

Если у вас есть вызов по значению, но фактическое значение является ссылочным типом или типом указателя, то сам "значение" не очень интересно (например, в C это всего лишь целое число определенного для платформы размера) - что интересно, что это значение указывает на.

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

Заимствовать аналогию с URL снова, тот факт, что я дал вам копию URL-адреса на веб-сайт, не особенно интересен, если мы заботимся о том, что веб-сайт, а не веб-сайт URL. Тот факт, что вы нацарапаете свою копию URL-адреса, не влияет на мою копию URL-адреса, это не то, о чем мы заботимся (и на самом деле, на таких языках, как Java и Python, "URL" или ссылочное значение типа, 't быть измененным вообще, только вещь, на которую он указывает, может).

Барбара Лисков, когда она придумала язык программирования CLU (который имел эти семантики), понял, что существующие термины "вызов по значению" и "вызов по ссылке" не были особенно полезны для описания семантики этого нового языка. Поэтому она придумала новый термин: вызов путем совместного использования объектов.

При обсуждении языков, которые технически вызывают по значению, но где обычные типы используются, являются ссылочными или указательными типами (то есть: почти каждый современный императивный, объектно-ориентированный или многопарадигменный язык программирования), я нахожу его много менее запутанным, чтобы просто не говорить о вызове по значению или звонить по ссылке. Придерживайтесь вызова путем совместного использования объектов (или просто вызов по объекту), и никто не будет путать.: -)

+58
источник

Вот пример:

#include <iostream>

void by_val(int arg) { arg += 2; }
void by_ref(int&arg) { arg += 2; }

int main()
{
    int x = 0;
    by_val(x); std::cout << x << std::endl;  // prints 0
    by_ref(x); std::cout << x << std::endl;  // prints 2

    int y = 0;
    by_ref(y); std::cout << y << std::endl;  // prints 2
    by_val(y); std::cout << y << std::endl;  // prints 2
}
+52
источник

Прежде чем понимать 2 условия, вы ДОЛЖНЫ понимать следующее. Каждый объект имеет две вещи, которые могут отличить его.

  • Его ценность.
  • Его адрес.

Так что если вы скажете employee.name = "John"

знайте, что есть 2 вещи о name. Его значение, которое есть "John" а также его расположение в памяти, которое является шестнадцатеричным числом, может быть примерно таким: 0x7fd5d258dd00.

В зависимости от языковой архитектуры или типа (класса, структуры и т.д.) Вашего объекта вы будете либо передавать "John" либо 0x7fd5d258dd00

Передача "John" известна как передача по значению. Передача 0x7fd5d258dd00 известна как передача по ссылке. Любой, кто указывает на это место памяти, будет иметь доступ к значению "John".

Подробнее об этом я рекомендую прочитать о разыменовании указателя, а также о том, почему вы выбираете struct (тип значения) над классом (тип ссылки)

+45
источник

Самый простой способ получить это в файле Excel. Скажем, например, что у вас есть два числа, 5 и 2 в ячейках A1 и B1 соответственно, и вы хотите найти их сумму в третьей ячейке, скажем, A2. Вы можете сделать это двумя способами.

  • Либо передавая свои значения ячейке A2, введя в эту ячейку = 5 + 2. В этом случае, если значения ячеек A1 или B1 меняются, сумма в A2 остается неизменной.

  • Или посредством передачи "ссылок" ячеек A1 и B1 в ячейку A2 путем ввода = A1 + B1. В этом случае, если значения ячеек A1 или B1 меняются, сумма в A2 также изменяется.

+22
источник

Сравнение: Значение по сравнению с ссылкой

Пройти по значению Локальными параметрами являются копии исходных аргументов, переданных в Изменения, сделанные в функции этих переменных , не влияют на оригиналы

Перейдите по ссылке Локальные параметры - это ссылки на места хранения исходных аргументов, переданных в. Изменения к этим переменным в функции будут влиять на оригиналы Копирование не производится, поэтому сохраняются накладные расходы на копирование (время, хранение).

+19
источник

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

+18
источник

Передача по значению отправляет КОПИЮ данных, хранящихся в указанной вами переменной, передает по ссылке, отправляет прямую ссылку на эту переменную. Поэтому, если вы передаете переменную по ссылке и затем измените переменную внутри блока, в который вы ее передали, исходная переменная будет изменена. Если вы просто пройдете по значению, исходная переменная не сможет быть изменена блоком, в который вы его передали, но вы получите копию того, что она содержала во время вызова.

+9
источник

Основное различие между ними заключается в том, что переменные типа значения хранят значения, поэтому указание переменной типа значения в вызове метода передает копию этого значения переменной в метод. Переменные ссылочного типа хранят ссылки на объекты, поэтому указание переменной ссылочного типа в качестве аргумента передает методу копию фактической ссылки, которая ссылается на объект. Даже если сама ссылка передается по значению, метод может использовать полученную ссылку для взаимодействия с исходным объектом и, возможно, для его изменения. Аналогично, при возврате информации из метода через оператор return метод возвращает копию значения, хранящегося в переменной типа значения, или копию ссылки, хранящейся в переменной типа ссылки. Когда ссылка возвращается, вызывающий метод может использовать эту ссылку для взаимодействия с указанным объектом. Таким образом, по сути, объекты всегда передаются по ссылке.

В С# для передачи переменной по ссылке, чтобы вызываемый метод мог изменять переменные, С# предоставляет ключевые слова ref и out. Применение ключевого слова ref к объявлению параметра позволяет передавать переменную в метод по ссылке - вызываемый метод сможет изменять исходную переменную в вызывающей стороне. Ключевое слово ref используется для переменных, которые уже были инициализированы в вызывающем методе. Обычно, когда вызов метода содержит неинициализированную переменную в качестве аргумента, компилятор генерирует ошибку. Предшествующий параметр с ключевым словом out создает выходной параметр. Это указывает компилятору, что аргумент будет передан в вызываемый метод по ссылке и что вызываемый метод назначит значение исходной переменной в вызывающей программе. Если метод не присваивает значение выходному параметру на каждом возможном пути выполнения, компилятор генерирует ошибку. Это также препятствует тому, чтобы компилятор генерировал сообщение об ошибке для неинициализированной переменной, которая передается в качестве аргумента методу. Метод может возвратить вызывающей стороне только одно значение с помощью оператора return, но может вернуть много значений, указав несколько выходных (ref и/или out) параметров.

см. обсуждение С# и примеры здесь, текст ссылки

+5
источник

Передача по значению - Функция копирует переменную и работает с копией (поэтому она не меняет ничего в исходной переменной)

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

Пример (скопируйте и используйте/попробуйте сами и посмотрите):

#include <iostream>

using namespace std;

void funct1(int a){ //pass-by-value
    a = 6; //now "a" is 6 only in funct1, but not in main or anywhere else
}
void funct2(int &a){ //pass-by-reference
    a = 7; //now "a" is 7 both in funct2, main and everywhere else it'll be used
}

int main()
{
    int a = 5;

    funct1(a);
    cout<<endl<<"A is currently "<<a<<endl<<endl; //will output 5
    funct2(a);
    cout<<endl<<"A is currently "<<a<<endl<<endl; //will output 7

    return 0;
}

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

+4
источник

Примеры:

class Dog 
{ 
public:
    barkAt( const std::string& pOtherDog ); // const reference
    barkAt( std::string pOtherDog ); // value
};

const &, как правило, лучше всего. Вы не берете на себя штраф за строительство и уничтожение. Если ссылка не const, ваш интерфейс предполагает, что он изменит переданные данные.

+3
источник

Короче говоря, Passed by value является WHAT и передается по ссылке WHERE.

Если ваше значение VAR1 = "Счастливый парень!", вы увидите только "Счастливый парень!". Если VAR1 изменится на "Happy Gal!", Вы этого не узнаете. Если он будет передан по ссылке, а VAR1 изменится, вы будете.

+2
источник

Если вы не хотите изменять значение исходной переменной после ее передачи в функцию, функция должна быть построена с параметром " pass by value ".

Тогда функция будет иметь ТОЛЬКО значение, но не адрес переданной переменной. Без адреса переменной код внутри функции не может изменить значение переменной, как видно снаружи функции.

Но если вы хотите дать функции возможность изменять значение переменной, как видно снаружи, вам нужно использовать передачу по ссылке. Поскольку и значение, и адрес (ссылка) передаются и доступны внутри функции.

+1
источник

По определению pass by value означает, что вы делаете копию в памяти фактического значения параметра, которое передается, копия содержимого фактического параметра. Используйте pass by value, когда вы только "используете" параметр для некоторых вычислений, не изменяя его для клиентской программы.

В проходе по ссылке (также называемой pass by address) сохраняется копия адреса фактического параметра. Используйте pass by reference при изменении параметра, переданного клиентской программой.

+1
источник

pass by value означает, как передать значение функции, используя аргументы. в проходе по значению мы копируем данные, хранящиеся в указанной нами переменной, и она медленнее, чем pass by reference bcse t он копирует данные. мы вносим изменения в скопированные данные, исходные данные не затрагиваются. nd в pass by refernce или передать по адресу, мы отправляем прямую ссылку на самую переменную. или передавая указатель на переменную. это быстрее bcse меньше времени потребляется

+1
источник

Вот пример, демонстрирующий различия между передачей по значению - значением указателя - ссылкой:

void swap_by_value(int a, int b){
    int temp;

    temp = a;
    a = b;
    b = temp;
}   
void swap_by_pointer(int *a, int *b){
    int temp;

    temp = *a;
    *a = *b;
    *b = temp;
}    
void swap_by_reference(int &a, int &b){
    int temp;

    temp = a;
    a = b;
    b = temp;
}

int main(void){
    int arg1 = 1, arg2 = 2;

    swap_by_value(arg1, arg2);
    cout << arg1 << " " << arg2 << endl;    //prints 1 2

    swap_by_pointer(&arg1, &arg2);
    cout << arg1 << " " << arg2 << endl;    //prints 2 1

    arg1 = 1;                               //reset values
    arg2 = 2;
    swap_by_reference(arg1, arg2);
    cout << arg1 << " " << arg2 << endl;    //prints 2 1
}

Метод "передача по ссылке" имеет важное ограничение. Если параметр объявлен как передан ссылкой (поэтому ему предшествует знак и), его соответствующий действительный параметр должен быть переменной.

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

Функция не может поместить значение в нечто иное, чем переменная. Он не может назначить новое значение литералу или заставить выражение изменить его результат.

PS: Вы также можете проверить ответ Дилана Битти в текущем потоке, который объясняет это простыми словами.

0
источник

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

По ссылке: Когда аргументы передаются по ссылке, это означает, что ссылка на ссылку или указатель на действительную переменную передается методу, а не фактические данные переменных.

Отметьте статью для получения дополнительных примеров.

0
источник

Посмотрите другие вопросы по меткам или Задайте вопрос