Указатель против ссылки
Что было бы лучше при предоставлении функции исходной переменной для работы с:
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);
}
Ответ 7
Используйте ссылку, когда можете, используйте указатель, когда вам нужно.
Из С++ FAQ: "Когда следует использовать ссылки и когда следует использовать указатели?"
Ответ 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
Ответ 9
Ссылка - это неявный указатель. В основном вы можете изменить значение, на которое ссылаются контрольные точки, но вы не можете изменить ссылку, чтобы указать на что-то другое. Итак, мои 2 цента - это то, что если вы хотите изменить значение параметра, передайте его как ссылку, но если вам нужно изменить параметр, чтобы указать на другой объект, передайте его с помощью указателя.
Ответ 10
Рассмотрим ключевое слово С# out. Компилятор требует, чтобы вызывающий метод применял ключевое слово out для любых аргументов, даже если он уже знает, если они есть. Это предназначено для повышения удобочитаемости. Хотя с современными IDE я склонен думать, что это задание для синтаксического (или смыслового) выделения.
Ответ 11
Перейдите по ссылке const, если нет причины, по которой вы хотите изменить/сохранить содержимое, которое вы проходите.
Это наиболее эффективный метод в большинстве случаев.
Убедитесь, что вы используете const для каждого параметра, который вы не хотите изменять, поскольку это не только защищает вас от выполнения чего-то глупого в функции, но и дает другим пользователям представление о том, что функция выполняет с переданными значениями. Это включает в себя создание указателя const, когда вы хотите изменить то, что указало на...
Ответ 12
указатели:
- Может быть назначен
nullptr
(или NULL
). - На сайте вызова вы должны использовать
&
если ваш тип не является указателем сам по себе, то есть вы явно модифицируете свой объект. - Указатели могут быть отскок.
Рекомендации:
- Не может быть нулевым.
- После привязки не может измениться.
- Абоненты не должны явно использовать
&
. Это иногда считается плохим, потому что вы должны перейти к реализации функции, чтобы увидеть, был ли изменен ваш параметр.
Ответ 13
Ссылка похожа на указатель, за исключением того, что вам не нужно использовать префикс ∗ для доступа к значению, на которое ссылается ссылка. Кроме того, нельзя сделать ссылку на другой объект после его инициализации.
Ссылки особенно полезны для указания аргументов функции.
Для получения дополнительной информации см. "Путешествие по C++" Бьярна Страуструпа (2014). Страницы 11-12.