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

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

unsigned long x = 4;

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

или

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

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

Ответы

Ответ 1

Мое правило:

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

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

Ответ 2

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

  • Как и во всех других местах, всегда < <20 > -коррект.

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

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

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

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

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

    • Обоснование: мы не хотим разбить пункт 2...
  • Выберите "передать по значению" над "pass by const reference", только если это значение POD (Обычная старая структура данных) или достаточно маленькое (память ) или другими способами достаточно дешево (по времени) для копирования.

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

Ответ 3

В конечном итоге это становится субъективным. Обсуждение до сих пор полезно, но я не думаю, что есть правильный или решительный ответ на это. Многое будет зависеть от стиля руководства и ваших потребностей в то время.

Хотя есть несколько различных возможностей (независимо от того, может ли что-либо быть NULL) с указателем, наибольшее практическое различие для выходного параметра - это чисто синтаксис. Например, руководство по стилю Google C++ (https://google.github.io/styleguide/cppguide.html#Reference_Arguments) обязывает только указатели для выходных параметров и разрешает только ссылки, которые являются константными. Аргументация заключается в удобочитаемости: что-то с синтаксисом значения не должно иметь семантического значения указателя. Я не предполагаю, что это обязательно правильно или неправильно, но я думаю, что дело здесь в том, что это вопрос стиля, а не правильности.

Ответ 4

Вы должны передать указатель, если собираетесь изменить значение переменной. Несмотря на то, что техническая передача ссылки или указателя одинакова, передача указателя в вашем случае использования более читаема, поскольку она "рекламирует" тот факт, что значение будет изменено функцией.

Ответ 5

Указатели Vs. Refereces

Ссылки менее мощные, чем указатели:

1) После создания ссылки впоследствии нельзя ссылаться на другой объект; он не может быть пересмотрен. Это часто делается с указателями.

2) Ссылки не могут быть NULL. Указатели часто делают NULL, чтобы указать, что они не указывают на какую-либо действительную вещь.

3) При объявлении эта ссылка должна быть инициализирована. Нет такого ограничения с указателями

Из-за вышеуказанных ограничений ссылки на С++ не могут использоваться для реализации структур данных, таких как Linked List, Tree и т.д. В Java ссылки не имеют ограничений и могут быть использованы для реализации всех структуры данных. Ссылки, более мощные в Java, являются основной причиной, по которой Java не нуждается в указателях.

Ссылки более безопасны и просты в использовании:

1) Безопаснее: поскольку ссылки должны быть инициализированы, дикие ссылки, такие как дикие указатели, вряд ли будут существовать. По-прежнему возможно иметь ссылки, которые не относятся к допустимому местоположению

2) Прост в использовании: для доступа к значению не требуется оператор разыменования. Они могут использоваться как обычные переменные. "& Амп; оператор нужен только во время объявления. Кроме того, к элементам ссылки объекта можно обращаться с помощью оператора точки ('.), В отличие от указателей, в которых для доступа к элементам необходим оператор стрелки (- > ).

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

Ответ 6

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

Лучшее решение в большинстве случаев (с точки зрения безопасности) - это использовать boost :: option. Это позволяет передавать необязательные значения по ссылке, а также в качестве возвращаемого значения.

// Sample method using optional as input parameter
void PrintOptional(const boost::optional<std::string>& 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<int> ReturnOptional(bool return_nothing)
{
    if (return_nothing)
    {
       return boost::optional<int>();
    }

    return boost::optional<int>(42);
}

Ответ 8

указатели

  • Указатель - это переменная, которая содержит адрес памяти.
  • Объявление указателя состоит из базового типа, * и имени переменной.
  • Указатель может указывать на любое количество переменных в жизни
  • Указатель, который в данный момент не указывает на допустимое место в памяти, получает значение null (которое равно нулю)

    BaseType* ptrBaseType;
    BaseType objBaseType;
    ptrBaseType = &objBaseType;
    
  • & Является унарным оператором, который возвращает адрес памяти своего операнда.

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

       int nVar = 7;
       int* ptrVar = &nVar;
       int nVar2 = *ptrVar;
    

Ссылка

  • Ссылка (&) похожа на псевдоним существующей переменной.

  • Ссылка (&) похожа на константный указатель, который автоматически разыменовывается.

  • Обычно используется для списков аргументов функции и возвращаемых значений функции.

  • Ссылка должна быть инициализирована при ее создании.

  • Как только ссылка инициализируется на объект, она не может быть изменена для ссылки на другой объект.

  • Вы не можете иметь пустые ссылки.

  • Ссылка 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
    

enter image description here

enter image description here

Ответ 9

Ссылка - это неявный указатель. В основном вы можете изменить значение, на которое ссылаются контрольные точки, но вы не можете изменить ссылку, чтобы указать на что-то другое. Итак, мои 2 цента - это то, что если вы хотите изменить значение параметра, передайте его как ссылку, но если вам нужно изменить параметр, чтобы указать на другой объект, передайте его с помощью указателя.

Ответ 10

Рассмотрим ключевое слово С# out. Компилятор требует, чтобы вызывающий метод применял ключевое слово out для любых аргументов, даже если он уже знает, если они есть. Это предназначено для повышения удобочитаемости. Хотя с современными IDE я склонен думать, что это задание для синтаксического (или смыслового) выделения.

Ответ 11

Перейдите по ссылке const, если нет причины, по которой вы хотите изменить/сохранить содержимое, которое вы проходите.

Это наиболее эффективный метод в большинстве случаев.

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

Ответ 12

указатели:

  • Может быть назначен nullptr (или NULL).
  • На сайте вызова вы должны использовать & если ваш тип не является указателем сам по себе, то есть вы явно модифицируете свой объект.
  • Указатели могут быть отскок.

Рекомендации:

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

Ответ 13

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

Ссылки особенно полезны для указания аргументов функции.

Для получения дополнительной информации см. "Путешествие по C++" Бьярна Страуструпа (2014). Страницы 11-12.