Я могу вообразить один случай, в котором входной параметр мог быть ПУСТЫМ так, чтобы передача указателем была предпочтена, но не передача ссылкой?
Кто-либо может добавить больше случаев?
Некоторым больше нравится передача по указателю в тех случаях, когда переданный объект действительно будет изменен. Они используют передачу по константной ссылке, когда объект передается по ссылке, чтобы избежать копирования объекта, но не будут изменены в функции.
В качестве иллюстрации возьмите следующие функции:
int foo(int x);
int foo1(int &x);
int foo2(int *x);
Теперь в коде я делаю следующее:
int testInt = 0;
foo(testInt); // can't modify testInt
foo1(testInt); // can modify testInt
foo2(&testInt); // can modify testInt
При вызове foo vs foo1 с точки зрения вызывающего абонента (или программиста, читающего код) не очевидно, что функция может изменять testInt без необходимости смотреть на сигнатуру функции. Глядя на foo2, читатель может легко увидеть, что функция на самом деле может изменять значение testInt, потому что функция получает адрес параметра. Обратите внимание, что это не гарантирует, что объект действительно изменен, но здесь помогает согласованность в использовании ссылок и указателей. В общем, если вы хотите последовательно следовать этому руководству, вы всегда должны передавать константные ссылки, когда вы хотите избежать копий, и передавать по указателю, когда вы хотите иметь возможность изменять объект.
В FAQ по C ++ есть очень хороший ответ на этот вопрос:
Используйте ссылки, когда можете, и {{1} } указатели, когда вам нужно.
Ссылки обычно предпочтительнее указателей , если вам не нужна "переустановка". Обычно это означает, что ссылки наиболее полезны в общедоступном интерфейсе класса . Ссылки обычно появляются на внешней стороне объекта , а указатели - внутри.
Исключением из приведенного выше является случай, когда для параметра функции или возвращаемого значения требуется "контрольная" ссылка - ссылка , которая не относится к {{1} } объект. Обычно это лучше всего сделать, возвращая / принимая указатель и придавая указателю NULL это особое значение (ссылки всегда должны псевдонимы объектов, а не разыменованных NULL указатель).
Примечание. Программисты на старом языке C иногда не любят ссылки, поскольку они предоставляют семантику ссылок, которая не явно указана в коде вызывающей стороны. Однако после некоторого опыта работы с C ++ можно быстро понять, что это форма сокрытия информации, которая является активом , а не помехой. Например, программисты должны писать код на языке задачи, а не на языке машины.
Когда вам нужно манипулировать (например, изменить размер, переназначить и т. Д.) Адресом, на который указывает указатель внутри функции, тогда вам понадобится указатель.
Например:
void f( int* p )
{
// ..
delete []p;
p = new int[ size ];
//...
}
В отличие от ссылок, значения указателей можно изменять и манипулировать ими.
В дополнение к некоторым другим ответам о семантике владения (особенно фабричных функциях).
Хотя это и не техническая причина, общее требование руководства по стилю состоит в том, что любые параметры, которые могут быть изменены, должны передаваться с помощью указателя. Это делает очевидным на callite, что объект может быть изменен.
void Operate(const int &input_arg, int *output_arg) {
*output_arg = input_arg + 1;
}
int main() {
int input_arg = 5;
int output_arg;
Foo(input_arg, &output_arg); // Passing address, will be modified!
}
В реальном программировании существует много ситуаций, в которых параметр не существует или является недопустимым, и это может зависеть от семантики кода во время выполнения. В таких ситуациях вы можете использовать NULL (0) для сигнала об этом состоянии. Кроме того,
Хотя, если достаточно времени потратить на правильную разработку кода, таких ситуаций можно избежать; на практике это возможно не каждый раз.
Правило номер один для этого: если NULL является допустимым значением для параметра функции в контексте функции, то передайте его как указатель, иначе передайте как ссылку.
Обоснование: если он не может (не должен!) Когда-либо быть NULL, то не стоит подвергать себя трудностям проверки на NULL или рисковать проблемами из-за того, что он является NULL.
При работе с необработанной памятью (например, при создании собственного пула памяти) вы можете использовать указатель. Но вы правы, в обычном коде указатель используется только в необязательном параметре.
В C ++ в большинстве случаев практически нет необходимости в передаче по указателю. Сначала вы должны рассмотреть альтернативы: шаблоны, (константные) ссылки, контейнеры, строки и интеллектуальные указатели. Тем не менее, если вы должны поддерживать устаревший код, вам нужно будет использовать указатели.Если ваш компилятор минималистичный (например, встроенные системы), вам понадобятся указатели. Если вам нужно поговорить с библиотекой C (какой-то системной библиотекой для конкретного драйвера, с которым вы работаете?), Тогда вам нужно будет работать с указателями. Если вы хотите иметь дело с очень конкретными смещениями памяти, вам понадобятся указатели.
В языке C указатели - первоклассные граждане, они слишком важны, чтобы думать об их устранении.
В любое время, когда вы передаете указатель функции. Или если у вас есть метод "сброса" а-ля auto_ptr.
Если мне нужно передать массив объектов, я должен передать его по указателю. Массивы не всегда хранятся в std::vector<>
.
Кроме того, передача по указателю допускает NULL, а передача по ссылке - нет, поэтому я использую это различие как контракт, подобно NULL
против NOT NULL
столбцов в SQL, а в свободном виде - как "функция, возвращающая bool
: true
= успешно и false
= неудачно, против функции, возвращающей int
: возвращаемое значение - код результата, где 0
= успех, а остальные - неудачи".
Это не является конкретной передачей аргументов, но влияет на передачу аргументов.
У вас может быть контейнер / совокупность указателей, но не ссылок. Хотя ссылки являются полиморфными, только указатели поддерживают операцию «обновления», которая важна для использования контейнера (тем более, что вы еще не можете инициализировать ссылки в массе, не уверен, изменит ли это агрегатные инициализаторы C ++ 0x).
Итак, если у вас есть контейнер, полный указателей, вы обычно будете управлять им с помощью функций, которые принимают указатели, а не ссылки.
Можно написать функцию, которая будет делать что-то с памятью, например, перераспределять ее, чтобы сделать больше (возвращая новый указатель).