Подтвердить что ты не робот

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

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

#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 Я чувствую (как я понял сейчас, это форма субъекта вкус), чтобы сделать более прозрачным

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

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

Чтобы сделать это в f2, вы обязательно должны префикс x с помощью &, так как там x является ссылкой в double, и вы хотите адрес.

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

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