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


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

#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 (там я знаю адрес и значение).

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

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

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

5   51   2011-04-28 13:49:28

5 ответов:

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

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

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

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

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

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 и не может быть перемещен.

ссылки не могут быть использованы для индексирования в простые массивы, такие как указатели.

в моей голове параметры функций всегда передаются по значению. Проходя мимо 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);

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

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

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

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