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

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

247 голосов
/ 22 сентября 2008

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

unsigned long x = 4;

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

или

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

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

Ответы [ 12 ]

273 голосов
/ 22 сентября 2008

Мое эмпирическое правило:

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

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

71 голосов
/ 22 сентября 2008

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

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

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

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

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

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

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

    • Обоснование: мы не хотим ломать пункт 2 ...
  4. Выбирайте «передача по значению» вместо «передача по константной ссылке», только если значение представляет собой POD ( Обычная старая структура данных ) или достаточно мало (по памяти) или другими дешевыми способами достаточно (по времени) для копирования.

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

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

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

7 голосов
/ 22 сентября 2008

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

5 голосов
/ 18 октября 2008

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

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

// 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);
}
4 голосов
/ 13 марта 2018

Pointers

  • Указатель - это переменная, которая содержит адрес памяти.
  • Объявление указателя состоит из базового типа, * и имени переменной.
  • Указатель может указывать на любое количество переменных в жизни
  • Указателю, который в данный момент не указывает на допустимое расположение в памяти, присваивается значение 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
    

enter image description here

enter image description here

4 голосов
/ 01 марта 2011

Используйте ссылку, когда можете, используйте указатель, когда вам нужно. Из C ++ FAQ: «Когда я должен использовать ссылки, а когда я должен использовать указатели?»

3 голосов
/ 18 октября 2008

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

3 голосов
/ 22 сентября 2008

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

2 голосов
/ 29 октября 2013

Указатели:

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

Ссылки:

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