Каковы преимущества передачи по указателю перед передачей по ссылке в C ++?
В последнее время я видел ряд примеров, в которых аргументы функции передаются по указателям, а не по ссылке. Есть ли преимущества для этого?
Пример:
func(SPRITE *x);
с вызовом
func(&mySprite);
против
func(SPRITE &x);
с вызовом
func(mySprite);
c++
pointers
parameter-passing
pass-by-reference
Мэтт Паско
источник
источник
new
создании указателя и возникающих в результате проблем владения.Ответы:
Указатель может получить параметр NULL, а ссылочный параметр - нет. Если есть вероятность, что вы захотите передать «нет объекта», используйте указатель вместо ссылки.
Кроме того, передача по указателю позволяет вам явно видеть на сайте вызова, передается ли объект по значению или по ссылке:
источник
func2 passes by reference
. Хотя я понимаю, что вы имели в виду, что он проходит «по ссылке» с точки зрения высокого уровня, реализуемого путем передачи указателя с точки зрения уровня кода, это было очень запутанным (см. Stackoverflow.com/questions/13382356/… ).func(int& a)
не является допустимым C в любой версии стандарта. Вы, вероятно, собираете свои файлы как C ++ случайно.Передача по указателю
nothing
. Это может быть использовано для предоставления необязательных аргументов.Передать по ссылке
string s = &str1 + &str2;
использовать указатели.void f(const T& t); ... f(T(a, b, c));
указатели не могут использоваться таким образом, поскольку вы не можете получить адрес временного объекта.источник
Мне нравится рассуждение статьи из "cplusplus.com:"
Из этого я понимаю, что основное различие между выбором указателя или ссылочного параметра заключается в том, что NULL является приемлемым значением. Вот и все.
В конце концов, в документации / комментариях к функции должно быть указано, является ли значение входным, выходным, изменяемым и т. Д.
источник
«Достаточно веревки, чтобы выстрелить себе в ногу» Аллена Холуба, перечисляет следующие 2 правила:
Он перечисляет несколько причин, по которым ссылки были добавлены в C ++:
const
ссылки позволяют вам иметь семантику передачи по значению, избегая при этом копированияЕго главная мысль заключается в том, что ссылки не должны использоваться в качестве выходных параметров, потому что на сайте вызова нет указаний на то, является ли параметр ссылкой или параметром-значением. Таким образом, его правило - использовать только
const
ссылки в качестве аргументов.Лично я думаю, что это хорошее эмпирическое правило, поскольку оно делает более понятным, когда параметр является выходным параметром или нет. Однако, хотя я лично согласен с этим в целом, я позволяю себе склоняться к мнению других членов моей команды, если они отстаивают выходные параметры в качестве ссылок (некоторым разработчикам они очень нравятся).
источник
Пояснения к предыдущим постам:
Ссылки НЕ являются гарантией получения ненулевого указателя. (Хотя мы часто относимся к ним как к таковым.)
В то время как ужасно плохой код, например, выводит вас из-за плохого кода, скомпилирует и запустит следующее: (По крайней мере, под моим компилятором.)
Реальная проблема, которую я имею со ссылками, связана с другими программистами, далее именуемыми IDIOTS , которые выделяют в конструкторе, освобождают в деструкторе и не могут предоставить конструктор копирования или оператор = ().
Внезапно возникает огромная разница между foo (BAR bar) и foo (BAR & bar) . (Автоматическая побитовая операция копирования вызывается. Удаление в деструкторе вызывается дважды.)
К счастью, современные компиляторы подберут это двойное освобождение одного и того же указателя. 15 лет назад они этого не сделали. (В gcc / g ++ используйте setenv MALLOC_CHECK_ 0, чтобы вернуться к старым способам.) В результате в DEC UNIX в одной и той же памяти выделяется два разных объекта. Там много отладочного веселья ...
Более практично:
источник
*i
, ваша программа имеет неопределенное поведение. Например, компилятор может увидеть этот код и предположить: «Хорошо, этот код имеет неопределенное поведение во всех путях кода, поэтому вся эта функция должна быть недоступна». Тогда предполагается, что все ветви, которые приводят к этой функции, не заняты. Это регулярно выполняемая оптимизация.Большинство ответов здесь не в состоянии устранить неоднозначность, присущую необработанному указателю в сигнатуре функции с точки зрения выражения намерения. Проблемы заключаются в следующем:
Вызывающая сторона не знает, указывает ли указатель на один объект или на начало «массива» объектов.
Вызывающая сторона не знает, «принадлежит» ли указатель памяти, на которую он указывает. IE, должна ли функция освободить память. (
foo(new int)
- Это утечка памяти?).Вызывающая сторона не знает,
nullptr
может ли она быть безопасно передана в функцию.Все эти проблемы решаются по ссылкам:
Ссылки всегда относятся к одному объекту.
Ссылки никогда не владеют памятью, к которой они относятся, они просто видят память.
Ссылки не могут быть нулевыми.
Это делает ссылки гораздо лучшим кандидатом для общего пользования. Тем не менее, ссылки не являются идеальными - есть несколько основных проблем, которые необходимо учитывать.
&
оператор, чтобы показать, что мы действительно передаем указатель. Например,int a = 5; foo(a);
здесь совершенно не ясно, что a передается по ссылке и может быть изменено.std::optional<T&>
это недопустимо (по уважительным причинам), указатели дают нам такую обнуляемость, которую вы хотите.Таким образом, кажется, что когда мы хотим пустую ссылку с явным косвенным обращением, мы должны достичь
T*
права? Неправильно!Абстракции
В нашем отчаянии за обнуляемость мы можем достичь
T*
и просто игнорировать все недостатки и семантическую двусмысленность, перечисленные ранее. Вместо этого мы должны достичь того, что C ++ делает лучше всего: абстракция. Если мы просто напишем класс, который обтекает указатель, мы получим выразительность, а также обнуляемость и явную косвенность.Это самый простой интерфейс, который я мог придумать, но он эффективно выполняет свою работу. Это позволяет инициализировать ссылку, проверять, существует ли значение и получать доступ к значению. Мы можем использовать это так:
Мы достигли наших целей! Давайте теперь посмотрим на преимущества по сравнению с необработанным указателем.
nullptr
можно передать, поскольку автор функции явно запрашиваетoptional_ref
Мы могли бы сделать интерфейс более сложным, например, добавив операторы равенства, монадику
get_or
иmap
интерфейс, метод, который получает значение или выдает исключение,constexpr
поддержку. Это может быть сделано вами.В заключение, вместо использования сырых указателей, подумайте о том, что эти указатели действительно означают в вашем коде, и либо используйте стандартную абстракцию библиотеки, либо напишите свою собственную. Это значительно улучшит ваш код.
источник
На самом деле, нет. Внутренне передача по ссылке осуществляется по существу передачей адреса объекта, на который есть ссылка. Таким образом, на самом деле нет никакого повышения эффективности при передаче указателя.
Однако передача по ссылке имеет одно преимущество. У вас гарантированно будет экземпляр любого объекта / типа, который передается. Если вы передадите указатель, то вы рискуете получить указатель NULL. Используя передачу по ссылке, вы отправляете неявную проверку NULL на один уровень вызывающей стороне вашей функции.
источник