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

Разница между указателем и ссылочным параметром?

Являются ли они такими же:

int foo(bar* p) {
  return p->someInt();
}

и

int foo(bar& r) {
  return r.someInt();
}

Игнорировать потенциал нулевого указателя. Являются ли эти две функции функционально идентичными независимо от того, является ли someInt() виртуальным или если они переданы a bar или подкласс bar?

Этот фрагмент ничего:

bar& ref = *ptr_to_bar;
4b9b3361

Ответ 1

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

Еще несколько отличий:

  • Вы не можете назначить NULL ссылке. Это ключевое различие, и Основная причина, по которой вы предпочли бы Другие.
  • Когда вы берете адрес указатель, вы получаете адрес переменная указателя. Когда вы берете адрес ссылки, вы получаете адрес переменной, являющейся упоминается.
  • Вы не можете переназначить ссылку. После инициализации он указывает на тот же объект на протяжении всей своей жизни.

Ответ 2

Игнорирование каждого синтаксического сахара и возможностей, которые могут быть сделаны с одним, а не с другим, и разница между указателями и ссылками, объясняемыми в других ответах (на другие вопросы)... Да, эти два функционально одинаковы! Оба вызова функции, и оба одинаково хорошо справляются с виртуальными функциями.

И нет, ваша строка не нарезается. Это просто привязывает ссылку непосредственно к объекту, на который указывает указатель.

Некоторые вопросы о том, почему вы хотели бы использовать один над другим:

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

Ответ 3

Ссылка является константным указателем, то есть вы не можете изменить ссылку для ссылки на другой объект. Если вы измените, изменится значение объекта ссылки.

Для Ex:

       int j = 10;
       int &i = j;
       int l = 20;
       i = l; // Now value of j = 20

       int *k = &j;
       k = &l;   // Value of j is still 10

Ответ 4

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

Также важно увидеть семантическую разницу:

  • Используйте ссылку, если вы действительно передадите объект нормальному - но он настолько велик, что имеет смысл передавать ссылку на объект, а не делать копию (если вы не изменяете объект, который есть).
  • Используйте указатель, если вы хотите иметь дело с адресом памяти, а не с объектом.

Ответ 5

Я не использовал C++ долгое время, поэтому я даже не собираюсь пытаться действительно ответить на ваш вопрос (извините); Тем не менее, Эрик Липперт только что опубликовал отличную статью о указателях/ссылках, на которые, как я полагал, я бы вам указал.

Ответ 6

Не уверен, что кто-то ответил на ваш второй вопрос, скрытый внизу о разрезе... нет, что не вызовет нарезки.

Нарезка - это когда производный объект присваивается (копируется) объекту базового класса - специализация производного класса "разрезана". Обратите внимание, что я сказал, что объект скопирован, мы не говорим о копировании/назначении указателей, но сами объекты.

В вашем примере это не происходит. Вы просто удаляете указатель на объект Bar (тем самым вызывая объект Bar), который используется как rvalue в инициализации ссылок. Не уверен, что я получил свою терминологию правильно...

Ответ 7

Как и все остальные, в ссылках на реализацию и указателях в основном то же самое. Есть некоторые незначительные оговорки:

  • Вы не можете назначить NULL ссылке (shoosh упомянул об этом): это так как нет "undefined" или "недействительная" ссылка значение.

  • Вы можете передать временный переменная как ссылка const, но не законно передавать указатель к временному.

Например, это нормально:

class Thingy; // assume a constructor Thingy(int,int)
void foo(const Thingy &a)
{ 
   a.DoSomething();
}

void bar( ) 
{
  foo( Thingy(1,2) );
}

но большинство компиляторов будут жаловаться на

void foo2( Thingy * a);

void bar2()
{
  foo( &Thingy(1,2) );
}
  • Взяв адрес переменной для получения указателя, он заставит компилятор сохранить его в памяти. Присвоение ссылки на локальную переменную просто создает синоним; в некоторых случаях это может позволить компилятору сохранить данные в регистре и избежать load-hit-store. Однако это применимо только к локальным переменным - как только что-то передается как параметр по ссылке, не избегая его сохранения в стек.

 

void foo()
{
   int a = 5;
   // this may be slightly more efficient
   int &b = a;
   printf( "%d", ++b );
   // than this
   int *c = &a;
   printf( "%d", ++(*c) );
}
  • Аналогично, __ limit keyword не может применяться к ссылкам, только указатели.

  • Вы не можете делать арифметику указателей со ссылками, поэтому, если у вас есть указатель на массив, то следующий элемент массива может быть получен через p + 1, ссылка только указывает на одну вещь в всю свою жизнь.

Ответ 8

Функции, очевидно, не "одинаковы", но в отношении виртуального поведения они будут вести себя одинаково. Что касается разрезания, это происходит только тогда, когда вы обрабатываете значения, а не ссылки или указатели.