Я могу представить один случай, в котором входной параметр может быть NULL, так что по-указателю предпочтительнее, но не по-ссылке?
Может ли кто-нибудь добавить больше случаев?
Я могу представить один случай, в котором входной параметр может быть NULL, так что по-указателю предпочтительнее, но не по-ссылке?
Может ли кто-нибудь добавить больше случаев?
Некоторым, таким как pass-by-pointer, лучше в тех случаях, когда передаваемый объект на самом деле будет изменен. Они используют pass-by-const-reference, когда объект передается ссылкой, чтобы избежать копирования объекта, но не будет изменяться в функции.
В качестве иллюстрации выполните следующие функции:
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, потому что функция получает адрес параметра. Обратите внимание, что это не гарантирует, что объект фактически изменен, но тот, который помогает в использовании ссылок или указателей. В общем, если вы хотите последовательно следовать этому руководству, вы всегда должны передавать ссылки const, когда хотите избежать копирования, и передавать указатель, когда хотите изменить объект.
С++ FAQ имеет очень хороший ответ на этот вопрос:
Используйте ссылки, когда можете, и указатели, когда вам нужно.
Ссылки обычно предпочтительнее указатели, когда вам не нужны "Переустановка". Это обычно означает, что ссылки наиболее полезны в класса. Рекомендации обычно появляются на коже объект и указатели внутри.
Исключением из вышеприведенного является то, что параметр функции или возвращаемое значение нуждается в "контрольной" ссылке - a ссылка, которая не относится к объект. Обычно это лучше всего делать возвращая/беря указатель и давая указатель NULL этот специальный значимость (ссылки всегда должны псевдонимы, а не NULL с разыменованием указатель).
Примечание. Программисты старой строки C иногда не нравятся ссылки, поскольку они предоставить ссылочную семантику, которая не является явно в коде вызывающего абонента. После однако опыт С++ быстро понимает, что это форма скрытие информации, которое является активом а не ответственности. Например., программисты должны писать код в языка проблемы, а не язык машины.
У вас много ситуаций в программировании реального мира, где параметр не существует или является недопустимым, и это может зависеть от семантики кода выполнения. В таких ситуациях вы можете использовать NULL (0) для сигнализации этого состояния. Кроме того,
Хотя, если достаточно потратить время на разработку кода, эти ситуации можно избежать; на практике это невозможно каждый раз.
В дополнение к некоторым другим ответам о семантике собственности (особенно функции factory).
Хотя это не техническая причина, общим требованием к руководству по стилю является то, что любые параметры, которые могут быть изменены, должны передаваться указателем. Это делает очевидным в callsite, что объект может быть изменен.
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 является допустимым значением для параметра функции в контексте функции, передайте его как указатель, иначе передайте его как ссылку.
Обоснование, если оно не может (не должно!) когда-либо быть NULL, тогда не ставьте себя на проблему с проверкой NULL или риском проблем из-за того, что он является NULL.
При работе с необработанной памятью (например, при создании собственного пула памяти) вы должны использовать указатель. Но вы правы, в обычном коде единственное использование для указателя - необязательный параметр.
В С++ в большинстве случаев мало нужно пропускать указатель. Сначала вы должны рассмотреть альтернативы: шаблоны, (const) ссылки, контейнеры, строки и интеллектуальные указатели. Тем не менее, если вы должны поддерживать устаревший код, вам нужно будет использовать указатели. Если ваш компилятор минималистичен (например, встроенные системы), вам понадобятся указатели. Если вам нужно поговорить с библиотекой C (какая-то системная библиотека для определенного драйвера, с которым вы работаете?), Вам нужно будет работать с указателями. Если вы хотите иметь дело с очень специфическими смещениями памяти, вам понадобятся указатели.
В C указатели являются первоклассными гражданами, они слишком фундаментальны, чтобы думать об их устранении.
Каждый раз, когда вы передаете указатель на функцию. Или если у вас есть метод "reset" a la auto_ptr.
Когда вам нужно манипулировать (например, изменять размер, переназначать и т.д.), адрес, на который указывает указатель внутри функции, тогда вам нужен указатель.
Например:
void f( int* p )
{
// ..
delete []p;
p = new int[ size ];
//...
}
В отличие от ссылок, значения указателей можно изменять и манипулировать.
Это не конкретная передача аргументов, но она влияет на передачу аргументов.
У вас может быть контейнер/совокупность указателей, но не ссылок. Хотя ссылки являются полиморфными, только указатели поддерживают операцию "обновления", которая необходима для использования в контейнере (тем более, что вы еще не можете инициализировать ссылки в массовом порядке, не уверены, изменит ли это инициализаторы С++ 0x).
Итак, если у вас есть контейнер с указателями, вы, как правило, будете управлять им с помощью функций, которые принимают указатели, а не ссылки.
Можно, возможно, написать какую-либо функцию, чтобы сделать что-то с памятью, например, перераспределить ее, чтобы увеличить ее (возвращая новый указатель).
Если мне нужно передать массив объектов, мне нужно пройти по указателю. Массивы не всегда хранятся в std::vector<>
.
Кроме этого, pass by pointer позволяет NULL и передавать по ссылке, нет, поэтому я использую это различие как контракт, похожий на столбцы NULL
vs. NOT NULL
в SQL, а также как функция return bool
: true
= удалось и false
= не удалось, vs. function return int
: return value - это код результата, где 0
= успех, а другие - сбои ".
Google, похоже, твердо придерживается этого мнения, и я склонен согласиться:
http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Reference_Arguments