Разница между аргументами функций, объявленными с помощью & и * в C ++ - PullRequest
53 голосов
/ 28 апреля 2011

Я набрал следующий пример:

#include <iostream>
double f(double* x, double* y)
{
    std::cout << "val x: " << *x << "\n";
    std::cout << "val y: " << *y << "\n";
    return *x * *y;
}
double f2(double &x, double &y)
{
    std::cout << "val x: " << x << "\n";
    std::cout << "val y: " << y << "\n";
    return x * y;
}
int main()
{
    double a, b;
    a = 2;
    b = 3; 
    std::cout << f(&a, &b) << "\n";
    std::cout << f2(a, b) << "\n";
    return 0;
}   

В функции f я объявляю x и y как указатели, значения которых я могу получить, используя *x. При вызове f мне нужно передать адрес моих переданных аргументов, поэтому я передаю &a, &b. f2 - то же самое, за исключением определения.

Теперь мой вопрос: действительно ли они одинаковы в отношении управления памятью? Оба не делают копию переданного значения, а вместо этого передают ссылку? Меня интересует f2, потому что я не мог прочитать адрес x в f2, поэтому я знаю больше о x и y в f (там я знаю адрес И значение).

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

Редактировать : Хорошо, спасибо, после еще нескольких исследований я нашел довольно полезную тему:

Указатель против ссылки Там также есть ссылка на правила кодирования Google http://google -styleguide.googlecode.com / svn / trunk / cppguide.xml # Reference_Arguments , что довольно useful Я чувствую (как я понял сейчас, это форма предметного вкуса) сделать больше ясно

Ответы [ 5 ]

52 голосов
/ 28 апреля 2011

f2 принимает аргументы по ссылке, что по сути является псевдонимом для передаваемых аргументов.Разница между указателем и ссылкой заключается в том, что ссылка не может быть NULL.С f вам нужно передать адрес (используя & оператор) параметров, которые вы передаете указателю, где при передаче по ссылке вы просто передаете параметры и создается псевдоним.

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

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

12 голосов
/ 28 апреля 2011

Это просто синтаксический сахар, чтобы не использовать * каждый раз, когда вы ссылаетесь на аргумент.Вы все еще можете использовать &, чтобы иметь адрес x в f2.

10 голосов
/ 28 апреля 2011

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

int X(10), Y(20);
int *pX = X;
int& rY = Y;

*pX = 15; // change value of X
rY = 25;  // change value of Y

pX = Y;   // pX now points to Y

rY всегда указывает на Y и не может быть перемещен.

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

6 голосов
/ 28 апреля 2011

В моей голове параметры функций всегда передаются по значению.Прохождение int легко представить, пропуск double просто больше, а пропуск struct или class действительно может быть очень большим.
Но, передав указатель на что-то, вы простоПередача адреса по значению. (Указатель часто является удобным размером для ЦП, как и int.)
Ссылка очень похожа, и, конечно, я думаю о ссылке как о указателе, но с синтаксическим сахаром, чтобы он выглядел как объект, на который он ссылается, был передан по значению.

Вы также можете думать о ссылке как о const указателе, то есть:

int i;
int j;
int* p = &i;           // pointer to i
int* const cp = p;     // cp points to i, but cp cannot be modified
p = &j;                // OK - p is modified to point to j
*cp = 0;               // OK - i is overwritten
cp = &j;               // ERROR - cp cannot be modified

int& ri = i;           // ri refers to i
ri = 1;                // i is overwritten
ri = j;                // i is overwritten again
                       // Did you think ri might refer to j?

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

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

void foo(int& i);

int* p = 0;
foo(*p);

Это означает, что указатели должны быть проверены перед их использованием, но ссылки не могут быть проверены.Реализация foo() может попытаться выполнить чтение или запись в i, что приведет к нарушению доступа.

В приведенном выше примере указатель p должен проверяться ранееиспользуется в вызове на foo:

if (p) foo(*p);
2 голосов
/ 28 апреля 2011

Вы должны были прочитать x адрес в обеих функциях.

Чтобы сделать это в f2, вы, конечно, должны префикс x на & с тех пор, x - это ссылка на двойное число, и вы хотите адрес .

Стоит отметить разницу между ссылками и указателями в том, что первые не могут быть NULL.Вы должны передать что-то (действительное), когда при указании указатель, вы должны указать в документации, разрешено ли / пропущено ли пропуск NULL.

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

...