Когда передача указателем предпочтена передаче ссылкой в C++?

Я могу вообразить один случай, в котором входной параметр мог быть ПУСТЫМ так, чтобы передача указателем была предпочтена, но не передача ссылкой?

Кто-либо может добавить больше случаев?

34
задан jamesdlin 31 March 2010 в 04:11
поделиться

12 ответов

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

В качестве иллюстрации возьмите следующие функции:

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

39
ответ дан 27 November 2019 в 16:22
поделиться

В FAQ по C ++ есть очень хороший ответ на этот вопрос:

Используйте ссылки, когда можете, и {{1} } указатели, когда вам нужно.

Ссылки обычно предпочтительнее указателей , если вам не нужна "переустановка". Обычно это означает, что ссылки наиболее полезны в общедоступном интерфейсе класса . Ссылки обычно появляются на внешней стороне объекта , а указатели - внутри.

Исключением из приведенного выше является случай, когда для параметра функции или возвращаемого значения требуется "контрольная" ссылка - ссылка , которая не относится к {{1} } объект. Обычно это лучше всего сделать, возвращая / принимая указатель и придавая указателю NULL это особое значение (ссылки всегда должны псевдонимы объектов, а не разыменованных NULL указатель).

Примечание. Программисты на старом языке C иногда не любят ссылки, поскольку они предоставляют семантику ссылок, которая не явно указана в коде вызывающей стороны. Однако после некоторого опыта работы с C ++ можно быстро понять, что это форма сокрытия информации, которая является активом , а не помехой. Например, программисты должны писать код на языке задачи, а не на языке машины.

23
ответ дан 27 November 2019 в 16:22
поделиться

Когда вам нужно манипулировать (например, изменить размер, переназначить и т. Д.) Адресом, на который указывает указатель внутри функции, тогда вам понадобится указатель.

Например:


void f( int* p )
{
    // ..

    delete []p;
    p = new int[ size ];

    //...
}

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

1
ответ дан 27 November 2019 в 16:22
поделиться

В дополнение к некоторым другим ответам о семантике владения (особенно фабричных функциях).

Хотя это и не техническая причина, общее требование руководства по стилю состоит в том, что любые параметры, которые могут быть изменены, должны передаваться с помощью указателя. Это делает очевидным на 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!
}
4
ответ дан 27 November 2019 в 16:22
поделиться

В реальном программировании существует много ситуаций, в которых параметр не существует или является недопустимым, и это может зависеть от семантики кода во время выполнения. В таких ситуациях вы можете использовать NULL (0) для сигнала об этом состоянии. Кроме того,

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

Хотя, если достаточно времени потратить на правильную разработку кода, таких ситуаций можно избежать; на практике это возможно не каждый раз.

6
ответ дан 27 November 2019 в 16:22
поделиться

Правило номер один для этого: если NULL является допустимым значением для параметра функции в контексте функции, то передайте его как указатель, иначе передайте как ссылку.

Обоснование: если он не может (не должен!) Когда-либо быть NULL, то не стоит подвергать себя трудностям проверки на NULL или рисковать проблемами из-за того, что он является NULL.

4
ответ дан 27 November 2019 в 16:22
поделиться

При работе с необработанной памятью (например, при создании собственного пула памяти) вы можете использовать указатель. Но вы правы, в обычном коде указатель используется только в необязательном параметре.

1
ответ дан 27 November 2019 в 16:22
поделиться

В C ++ в большинстве случаев практически нет необходимости в передаче по указателю. Сначала вы должны рассмотреть альтернативы: шаблоны, (константные) ссылки, контейнеры, строки и интеллектуальные указатели. Тем не менее, если вы должны поддерживать устаревший код, вам нужно будет использовать указатели.Если ваш компилятор минималистичный (например, встроенные системы), вам понадобятся указатели. Если вам нужно поговорить с библиотекой C (какой-то системной библиотекой для конкретного драйвера, с которым вы работаете?), Тогда вам нужно будет работать с указателями. Если вы хотите иметь дело с очень конкретными смещениями памяти, вам понадобятся указатели.

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

1
ответ дан 27 November 2019 в 16:22
поделиться

В любое время, когда вы передаете указатель функции. Или если у вас есть метод "сброса" а-ля auto_ptr.

1
ответ дан 27 November 2019 в 16:22
поделиться

Если мне нужно передать массив объектов, я должен передать его по указателю. Массивы не всегда хранятся в std::vector<>.

Кроме того, передача по указателю допускает NULL, а передача по ссылке - нет, поэтому я использую это различие как контракт, подобно NULL против NOT NULL столбцов в SQL, а в свободном виде - как "функция, возвращающая bool: true = успешно и false = неудачно, против функции, возвращающей int: возвращаемое значение - код результата, где 0 = успех, а остальные - неудачи".

0
ответ дан 27 November 2019 в 16:22
поделиться

Это не является конкретной передачей аргументов, но влияет на передачу аргументов.

У вас может быть контейнер / совокупность указателей, но не ссылок. Хотя ссылки являются полиморфными, только указатели поддерживают операцию «обновления», которая важна для использования контейнера (тем более, что вы еще не можете инициализировать ссылки в массе, не уверен, изменит ли это агрегатные инициализаторы C ++ 0x).

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

2
ответ дан 27 November 2019 в 16:22
поделиться

Можно написать функцию, которая будет делать что-то с памятью, например, перераспределять ее, чтобы сделать больше (возвращая новый указатель).

0
ответ дан 27 November 2019 в 16:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: