Указатель против ссылки
Что было бы лучшей практикой при предоставлении функции исходной переменной для работы с:
unsigned long x = 4; void func1(unsigned long& val) { val = 5; } func1(x);
или:
void func2(unsigned long* val) { *val = 5; } func2(&x);
IOW: Есть ли какая-то причина выбирать один за другим?
- Причина, почему бы не иметь макрос DELETE для C ++
- Размещение звездочки в объявлениях указателей
- Указатели в c ++ после удаления
- Неинициализированные указатели в коде
- Можно ли программно определить размер массива C ++? А если нет, то почему?
- Почему некоторые люди предпочитают «T const &» над «const T &»?
- Почему бы не использовать указатели для всего на C ++?
- Создать новый объект C ++ по определенному адресу памяти?
- Что такое C-указатель, если не адрес памяти?
- Массив для разметки указателя и передачи многомерных массивов в функции
- Как выровнять указатель в C
- Неравномерные указатели на x86
- Псевдонимы, вызываемые разыменованием, нарушат правила строгого сглаживания
Мое правило:
Используйте указатели, если вы хотите сделать с ними арифметику указателей (например, увеличивая адрес указателя, чтобы пройти через массив), или если вам когда-либо нужно передать указатель NULL.
Используйте ссылки в противном случае.
Я действительно думаю, что вы выиграете от создания следующей функции, вызывающей правила кодирования:
-
Как и во всех других местах, всегда будьте
const
-корректными.- Примечание. Это означает, среди прочего, что только out-values (см. Пункт 3) и значения, переданные по значению (см. Пункт 4), могут не иметь спецификатора
const
.
- Примечание. Это означает, среди прочего, что только out-values (см. Пункт 3) и значения, переданные по значению (см. Пункт 4), могут не иметь спецификатора
-
Передавайте только значение по указателю, если значение 0 / NULL является допустимым входом в текущем контексте.
-
Обоснование 1: как вызывающий , вы видите, что все, что вы проходите, должно быть в работоспособном состоянии.
-
Обоснование 2: Как называется , вы знаете, что все, что приходит, находится в пригодном для использования состоянии. Следовательно, для этого значения для NULL-проверки или обработки ошибок не требуется.
-
Обоснование 3: Обоснования 1 и 2 будут применены к компилятору . Всегда проверяйте ошибки во время компиляции, если сможете.
-
-
Если аргумент функции является исходным значением, передайте его по ссылке.
- Обоснование: мы не хотим нарушать пункт 2 …
-
Выберите «передать по значению» над «pass by const reference», только если это значение POD ( Обычная старая структура данных ) или достаточно маленькое (по памяти) или другими способами, достаточно дешевое (по времени) для копирования.
- Обоснование: избегать ненужных копий.
- Примечание: достаточно маленькие и достаточно дешевые не являются абсолютными величинами.
В конечном итоге это становится субъективным. Обсуждение пока полезно, но я не думаю, что на это есть правильный или решающий ответ. В то время многое будет зависеть от руководства по стилю и ваших потребностей.
Хотя есть несколько разных возможностей (независимо от того, может ли это быть NULL) с указателем, наибольшая практическая разница для выходного параметра – это чисто синтаксис. Руководство по стилю C ++ для Google ( https://google.github.io/styleguide/cppguide.html#Reference_Arguments ), например, содержит только указатели для выходных параметров и позволяет использовать только ссылки, которые являются константами. Обоснование – одно из читаемости: что-то с синтаксисом значения не должно иметь смысловое значение указателя. Я не предполагаю, что это обязательно правильно или неправильно, но я думаю, что дело здесь в том, что это вопрос стиля, а не правильности.
Вы должны передать указатель, если собираетесь изменить значение переменной. Несмотря на то, что технически передача ссылки или указателя одинакова, передача указателя в ваш прецедент является более читаемой, поскольку она «рекламирует» тот факт, что значение будет изменено функцией.
Указатели против. Refereces
Ссылки менее мощные, чем указатели:
1) После создания ссылки не может быть позже сделана ссылка на другой объект; он не может быть пересмотрен. Это часто делается с указателями.
2) Ссылки не могут быть NULL. Указатели часто делают NULL, чтобы указать, что они не указывают на какую-либо действительную вещь.
3) При объявлении ссылка должна быть инициализирована. Нет такого ограничения с указателями
Из-за вышеуказанных ограничений ссылки на C ++ не могут использоваться для реализации структур данных, таких как Linked List , Tree и т. Д. В Java ссылки не имеют ограничений выше и могут использоваться для реализации всех структур данных. Ссылки, более мощные в Java, являются основной причиной, по которой Java не нуждается в указателях.
Ссылки более безопасны и проще в использовании:
1) Безопаснее: поскольку ссылки должны быть инициализированы, дикие ссылки, такие как дикие указатели, вряд ли будут существовать. По-прежнему возможно иметь ссылки, которые не относятся к допустимому местоположению
2) Прост в использовании: для доступа к значению ссылки не требуется оператор разыменования. Они могут использоваться как обычные переменные. Оператор ‘&’ необходим только во время объявления. Кроме того, к элементам ссылки объекта можно обращаться с помощью оператора точки (‘.’), В отличие от указателей, в которых оператор стрелки (->) необходим для доступа к элементам.
Вместе с вышеупомянутыми причинами существует несколько мест, таких как аргумент конструктора копирования, где указатель не может использоваться. Ссылка должна использоваться, чтобы передать аргумент в конструкторе копирования. Аналогичным образом ссылки должны использоваться для перегрузки некоторых операторов, таких как ++ .
Если у вас есть параметр, где вам может потребоваться указать отсутствие значения, обычно принято указывать значение указателя и передавать его в NULL.
Лучшим решением в большинстве случаев (с точки зрения безопасности) является использование boost :: optional . Это позволяет передавать необязательные значения по ссылке, а также в качестве возвращаемого значения.
// Sample method using optional as input parameter void PrintOptional(const boost::optional& optional_str) { if (optional_str) { cout << *optional_str << std::endl; } else { cout << "(no string)" << std::endl; } } // Sample method using optional as return value boost::optional ReturnOptional(bool return_nothing) { if (return_nothing) { return boost::optional (); } return boost::optional (42); }
Используйте ссылку, когда можете, используйте указатель, когда вам нужно. Из часто задаваемых вопросов на C ++: «Когда следует использовать ссылки и когда следует использовать указатели?»
Ссылка – это неявный указатель. В основном вы можете изменить значение, на которое ссылаются контрольные точки, но вы не можете изменить ссылку, чтобы указать на что-то другое. Итак, мои 2 цента состоят в том, что если вы хотите изменить значение параметра, передайте его как ссылку, но если вам нужно изменить параметр, чтобы указать на другой объект, передайте его с помощью указателя.
Рассмотрим ключевое слово C #. Компилятор требует, чтобы вызывающий метод применял ключевое слово out для любых аргументов, даже если он уже знает, если они есть. Это предназначено для повышения удобочитаемости. Хотя с современными IDE я склонен думать, что это работа для синтаксического (или семантического) выделения.
Перейдите по ссылке const, если нет причины, по которой вы хотите изменить / сохранить содержимое, которое вы проходите.
Это наиболее эффективный метод в большинстве случаев.
Убедитесь, что вы используете const для каждого параметра, который вы не хотите изменять, поскольку это не только защищает вас от выполнения чего-то глупого в функции, но и дает хорошим указаниям другим пользователям, что функция выполняет с переданными значениями. Это включает в себя создание указателя const, когда вы хотите изменить то, что указало на …
указатели:
- Может быть назначен
nullptr
(илиNULL
). - На сайте вызова вы должны использовать &, если ваш тип не является самим указателем, в результате чего вы изменяете свой объект.
- Указатели могут восстанавливаться.
Рекомендации:
- Не может быть null.
- После привязки не может измениться.
- Звонящим не нужно явно использовать &. Это иногда считается плохим, потому что вы должны перейти к реализации функции, чтобы узнать, изменен ли ваш параметр.
указатели
- Указатель – это переменная, содержащая адрес памяти.
- Объявление указателя состоит из базового типа, * и имени переменной.
- Указатель может указывать на любое количество переменных во время жизни
-
Указатель, который в настоящее время не указывает на допустимую ячейку памяти, получает значение null (которое равно нулю)
BaseType* ptrBaseType; BaseType objBaseType; ptrBaseType = &objBaseType;
-
& – это унарный оператор, который возвращает адрес памяти своего операнда.
-
Оператор разыменования (*) используется для доступа к значению, хранящемуся в переменной, на которую указывает указатель.
int nVar = 7; int* ptrVar = &nVar; int nVar2 = *ptrVar;
Справка
-
Ссылка (&) похожа на псевдоним существующей переменной.
-
Ссылка (&) похожа на постоянный указатель, который автоматически разыменовывается.
-
Он обычно используется для списков аргументов функций и возвращаемых значений функции.
-
Ссылка должна быть инициализирована, когда она создана.
-
Когда ссылка инициализируется объектом, ее нельзя изменить, чтобы ссылаться на другой объект.
-
У вас не может быть ссылок NULL.
-
Ссылка const может ссылаться на const int. Это делается с временной переменной со значением const
int i = 3; //integer declaration int * pi = &i; //pi points to the integer i int& ri = i; //ri is refers to integer i – creation of reference and initialization