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

С++: разница между амперсандами "&" и "звездочкой" * в объявлении функции/метода?

Есть ли какая-то тонкая разница между ними:

void a1(float &b) {
    b=1;
};
a1(b);

и

void a1(float *b) {
    (*b)=1;
};
a1(&b);

?

Оба они делают то же самое (или так кажется из main()), но первый явно короче, однако большая часть кода, который я вижу, использует вторую нотацию. Есть ли разница? Может быть, в случае, если какой-то объект вместо float?

4b9b3361

Ответ 2

Да. Обозначение * гласит, что то, что проходит в стеке, является указателем, то есть адресом чего-то. & говорит, что это ссылка. Эффект подобен, но не идентичен:

Возьмем два случая:

   void examP(int* ip);
   void examR(int& i);

   int i;

Если я вызываю examP, пишу

   examP(&i);

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

   examR(i);

Мне это не нужно; теперь компилятор "каким-то образом" передает ссылку - что практически означает, что он получает и передает адрес i. На стороне кода, тогда

   void examP(int* ip){
        *ip += 1;
   }

Я должен обязательно разыменовать указатель. ip += 1 делает что-то совсем другое.

   void examR(int& i){
        i += 1;
   }

всегда обновляет значение i.

Чтобы больше задуматься, прочитайте "вызов по ссылке" против "вызов по значению". Понятие & дает вызов С++ по ссылке.

Ответ 3

В первом примере со ссылками вы знаете, что b не может быть NULL. С примером указателя b может быть указателем NULL.

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

a1(*(float *)NULL);

Ответ 4

Во втором примере вызывающий должен префикс имени переменной '&' для передачи адреса переменной.

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

Ответ 5

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

Ответ 6

Функционально в вашем примере обе версии делают то же самое.

Первое имеет то преимущество, что оно прозрачно на стороне вызова. Представьте себе, как он будет искать оператора:

cin >> &x;

И как это выглядит уродливым для вызова подкачки

swap(&a, &b);

Вы хотите поменять местами a и b. И это выглядит намного лучше, чем когда вы сначала должны принять адрес. Кстати, bjarne stroustrup пишет, что основной причиной ссылок была прозрачность, которая была добавлена ​​на стороне вызова - особенно для операторов. Также посмотрите, как это не очевидно, будет ли следующий

&a + 10

Добавил бы 10 к содержанию a, вызвав его оператор +, или добавит 10 к временному указателю на a. Добавьте это к невозможности, чтобы вы не могли перегружать операторов только встроенными операндами (например, указателем и целым числом). Ссылки делают этот кристалл ясным.

Указатели полезны, если вы хотите, чтобы у вас было значение "null":

a1(0);

Затем в a1 метод может сравнивать указатель с 0 и видеть, указывает ли указатель на любой объект.

Ответ 7

Одна большая разница, которую стоит отметить, это то, что происходит снаружи, вы либо имеете:

a1(something);

или

a1(&something);

Мне нравится передавать аргументы по ссылке (всегда константа одна:)), когда они не изменяются в функции/методе (а затем вы также можете передавать автоматически/временные объекты внутри) и передавать их указателем на оповещение и оповещение пользователь/читатель кода, вызывающего метод, который аргумент может и, возможно, намеренно модифицирован внутри.