Пересмотр Call-By-Value и Call-By-Reference

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

Мой вопрос в конце сводится к этому. Почему вызов Java по значению и вызов С++ по ссылке (при использовании указателей)?

Рассмотрим вызов метода в Java при передаче ссылок и в C++ при передаче указателей. В конце концов, в обоих случаях я могу вносить изменения, которые видны вызывающему абоненту. Также в обоих случаях я передаю адрес объекта в функцию. На самом деле я копирую, то есть делаю вызов по значению в С++ тоже при передаче указателя, не так ли?

Вы можете просто проверить это обстоятельство, запустив следующий код:

#include <iostream>

void modify (int *i) {
    int a = 5;
    i = &a;
}

int main () {
    int b;
    int *i = &b;
    std::cout << i << std::endl;
    modify(i);
    std::cout << i << std::endl;
    return 0;
}

Который будет печатать два раза один и тот же адрес.

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

Заранее спасибо.


person ben    schedule 20.01.2014    source источник
comment
Почему вызов Java по значению и вызов С++ по ссылке (при использовании указателей)? Потому что люди, разрабатывавшие языки, определили их именно так.   -  person twalberg    schedule 20.01.2014


Ответы (2)


Мой вопрос в конце сводится к этому. Почему вызов Java по значению и вызов С++ по ссылке (при использовании указателей)?

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

person TypeIA    schedule 20.01.2014
comment
@ user2820379 указатель, передаваемый по значению, может использоваться для изменения объекта, на который он указывает (но не указателя), точно так же, как когда java передает ссылку по значению, его можно использовать для изменения объекта, на который он ссылается (но не ссылка ). - person user3125280; 21.01.2014
comment
Звучит совершенно интуитивно для меня. Я просто запутался, так как С++ часто называют поддержкой вызова по ссылке. - person ben; 21.01.2014
comment
@user2820379 user2820379 Вызов по значению означает, что весь код вызываемого объекта видит только «значение» объекта, то есть копию. Вызов по ссылке означает, что весь код вызываемого объекта видит ссылку на объект. Вы по-прежнему можете передавать ссылку на объект по значению/копии в вызове по значению языка и передавать ссылку на копию/значение при вызове по эталонному языку. - person user3125280; 21.01.2014
comment
Я понимаю. Спасибо, что рассказали об этом. - person ben; 21.01.2014
comment
@ user2820379 C++ поддерживает аргументы по ссылке с использованием модификатора &. Но это не поведение по умолчанию. - person TypeIA; 21.01.2014
comment
@dvnrss Хотя под капотом передача по ссылке в C ++ на самом деле является просто синтаксическим удобством для передачи указателя по значению в большинстве реализаций. Примерно так же и в Java, несмотря на отсутствие указателей на уровне кода или любого другого языка, поддерживающего передачу по ссылке. В конце концов, ссылка — это в значительной степени расположение существующего объекта, который является либо указателем, либо смещением от какого-либо другого места, либо индексом в таблице, либо чем-то еще... - person twalberg; 22.01.2014

Пример, который вы приводите, является неуместным использованием вызова по ссылке. В функции modify

void modify (int *i) {
    int a = 5;
    i = &a;
}

Вы объявляете локальную переменную a, которая находится в стеке. Когда он выходит за пределы области видимости, его адрес не имеет смысла. Таким образом, назначение адреса a на i не влияет на то, на что указывает i.

Итак, вызов по ссылке работает, так как вы можете изменить значение того, на что указывает i в функции. Например:

void modify (int *i) {
    int a = 5;
    *i = a;
}

Поэтому в основной функции вы можете вызвать это так:

int b = 2;
int *i = &b;
std::cout << *i << std::endl;  //This will print 2
modify(i);
std::cout << *i << std::endl;  //This will prints 5
person tonga    schedule 20.01.2014
comment
Вы абсолютно правы. Пример, который я привел, имел только цель подчеркнуть, что указатели передаются по значению. - person ben; 20.01.2014