Звоните по ссылке в C ++ - PullRequest
       21

Звоните по ссылке в C ++

3 голосов
/ 08 марта 2010

Что фактически передается в вызове по ссылке на функцию?

void foo(int &a,int &b)

когда я пишу

foo(p,q)

что фактически передается в функцию. Это адрес p и q?

Ответы [ 5 ]

6 голосов
/ 08 марта 2010

То, что фактически передается функции, является ссылкой. Именованный параметр b становится синонимом объекта аргумента q.

Как компилятор, вероятно, реализует это так, что вызывающая сторона помещает адрес q в стек или в регистр перед вызовом, и вызывающий использует это значение для осуществления всех обращений к b. Но это может вводить в заблуждение, описывая это как «фактическую передачу» указателя, поскольку передача параметров является концепцией на уровне языка C ++, и на этом уровне это не то же самое, что передача указателя. Например, когда вы передаете указатель, вы можете передать нулевой указатель, но когда вы передаете ссылку, вы не можете (правильно). Поэтому было бы неправильно говорить, что это одно и то же.

Тем не менее, человек, реализующий компилятор, может описать его как «фактически передающий указатель», и вы знаете, что они имеют в виду. Для сравнения, если char переменные занимают 4-байтовые слоты стека в соглашении о вызовах, они могут сказать, что компилятор "фактически передает int". Так что это зависит от того, что «на самом деле» должно означать.

3 голосов
/ 08 марта 2010

В других ответах упоминается семантическая разница между ссылкой и указателем.

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

Вопрос уже задавался раньше: Какая разница между указателем и ссылкой на низком уровне?

2 голосов
/ 08 марта 2010

Это действительно передается ссылочный тип - это вроде как адрес, но не совсем. Фактический адрес будет указателем. Ссылки менее эффективны, чем указатели, но, возможно, безопаснее. Википедия содержит хорошее описание различий между указателями и ссылками.

1 голос
/ 08 марта 2010

Вы передаете ссылку, которая не является указателем и не адресом - но она похожа.

Что такое "точно" ссылка, не задокументирована.Стандарт не диктует механизмы обращения со справочной информацией - только последствия их использования. Обычно , они будут реализованы как указатели.

Пример:

int foo(int& a, int& b) { a = b; }

// Usage
int x, y;
foo(x, y);

Может генерироваться тот же машинный код, что и:

int foo(int* a, int* b) { *a = *b; }

// Usage
int x, y;
foo(&x, &y);

Но это не гарантируется, и они НЕ эквивалентны (хотя они предоставляют схожую функциональность).

Когда вы берете адрес ссылки, вы получаете тот же адрес, что и объект, на который она ссылается.Пример:

void foo(int& x) { std::cout << &x << std::endl; }

int y;
std::cout << &y << std::endl;
foo(); // This will print the same as above.
0 голосов
/ 08 марта 2010

Способ прохождения по ссылке определяется вашим компилятором. В любом случае они передаются как int&, что является фактическим типом в C ++. Попробуйте это:

int x = 10;
int& y = x;
x = 100;

Как вы думаете, что значение у? Ссылки не совсем указатели, а псевдонимы переменной. Тот же механизм, который применяется к вашему компилятору int&, используется для передачи по ссылочным параметрам.

Учитывая следующую программу:

void byRef(int& x)
{
    return;
}

void byVal(int x)
{
    return;
}

void byPtr(int * x)
{
    return;
}

int _tmain(int argc, _TCHAR* argv[])
{

    int x = 0;
    byRef(x);
    byVal(x);
    byPtr(&x);

    return 0;
}

Сборка MSVC90, сгенерированная для вызовов byRef и byPtr, точно такая же, как:

lea eax, [x]
push eax
call byRef ;or byPtr
add esp, 4
...