Указатель против ссылки

Что было бы лучшей практикой при предоставлении функции исходной переменной для работы с:

unsigned long x = 4; void func1(unsigned long& val) { val = 5; } func1(x); 

или:

 void func2(unsigned long* val) { *val = 5; } func2(&x); 

IOW: Есть ли какая-то причина выбирать один за другим?

Мое правило:

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

Используйте ссылки в противном случае.

Я действительно думаю, что вы выиграете от создания следующей функции, вызывающей правила кодирования:

  1. Как и во всех других местах, всегда будьте const -корректными.

    • Примечание. Это означает, среди прочего, что только out-values ​​(см. Пункт 3) и значения, переданные по значению (см. Пункт 4), могут не иметь спецификатора const .
  2. Передавайте только значение по указателю, если значение 0 / NULL является допустимым входом в текущем контексте.

    • Обоснование 1: как вызывающий , вы видите, что все, что вы проходите, должно быть в работоспособном состоянии.

    • Обоснование 2: Как называется , вы знаете, что все, что приходит, находится в пригодном для использования состоянии. Следовательно, для этого значения для NULL-проверки или обработки ошибок не требуется.

    • Обоснование 3: Обоснования 1 и 2 будут применены к компилятору . Всегда проверяйте ошибки во время компиляции, если сможете.

  3. Если аргумент функции является исходным значением, передайте его по ссылке.

    • Обоснование: мы не хотим нарушать пункт 2 …
  4. Выберите «передать по значению» над «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 

введите описание изображения здесь

введите описание изображения здесь

  • Преобразование указателя в указатель между производными и базовыми classами?
  • Что происходит, когда вы удаляете указатель дважды или больше на C ++?
  • Что такое тип данных uintptr_t
  • Как печатать переменные адреса в C?
  • Можно ли выделить функцию внутри массива и вернуть ее с помощью ссылки?
  • Возrotation массива с использованием C
  • Почему я не могу обработать массив как указатель в C?
  • Возвращаемый массив в функции
  • Передача 2D-массива функции C ++
  • Могу ли я взять адрес элемента «один конец прошлого» массива?
  • Является ли хорошей практикой освобождение NULL-указателя в C?
  • Давайте будем гением компьютера.