Подтвердить что ты не робот

Функции С++: амперсанд и звездочка

Скажем, у вас есть функция, которая изменяет переменную.

Если вы пишете это так: void myfunc(int *a) или как это void myfunc(int &a)?

Первая заставит вас вызвать функцию с помощью myfunc(&b), чтобы вызывающий абонент знал, что b будет изменен, но последний будет короче и может быть вызван просто с помощью myfunc(b). Так что лучше использовать? Есть ли что-то еще, что мне не хватает?

4b9b3361

Ответ 1

Указатели (т.е. "*" ) должны использоваться там, где значение "NULL" имеет смысл. Например, вы можете использовать NULL для представления того, что должен быть создан конкретный объект или что конкретного действия не требуется. Или если это когда-нибудь нужно вызвать из кода, отличного от С++. (например, для использования в совместно используемых библиотеках)

например. Функция libc time_t time (time_t *result);

Если result не равно NULL, текущее время будет сохранено. Но если result равно NULL, то никаких действий не предпринимается.

Если функция, которую вы пишете, не должна использовать NULL в качестве значимого значения, то использование ссылок (например, "&" ), вероятно, будет менее запутанным - если предположить, что это соглашение, которое использует ваш проект.

Ответ 2

По возможности я использую ссылки на указатели. Причина этого в том, что гораздо сложнее испортить ссылку, чем указатель. Люди всегда могут передавать NULL в значение указателя, но такой эквивалент ссылки не существует.

Единственным реальным недостатком является то, что ссылочные параметры в С++ имеют недостаток документации сайта вызова. Некоторые считают, что это затрудняет понимание кода (и я согласен в какой-то степени). Я обычно определяю следующее в своем коде и использую его для поддельной документации сайта сайта

#define byref
...
someFunc(byref x);

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

http://blogs.msdn.com/jaredpar/archive/2008/04/03/reference-values-in-c.aspx

Ответ 3

Я думаю, что я не согласен с @bb и @JaredPar, и я наклоняюсь к противоположной стороне забора. После нескольких лет попыток поддержки кода С++ других народов, я часто нахожу проблемы, скрывающиеся в неочевидных побочных эффектах ссылочных аргументов. С С# это очевидно, поскольку вы должны префикс типов аргументов с помощью 'ref'/'out', но ссылки потенциально сбивают с толку в С++. Итак, мне нравятся указатели, потому что действительно ясно, что что-то возвращается. Если вам не нравятся точки, С++ не для вас.

Ответ 4

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

Руководство по стилю Google С++ запрещает неконстантные ссылки.

Ответ 5

Первая заставит вас позвонить функцию с myfunc (& b), чтобы вызывающий что b будет изменен

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

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

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

Но это похоже на вопрос священной войны, у разных народов разные взгляды на этот вопрос. Например. google codding convension рекомендовал использовать указатели в аргументах, которые можно было изменить и разрешить только ссылки const: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Reference_Arguments

Все параметры, переданные по ссылке должен быть помечен как const.

Ответ 6

Мне нравится передавать по ссылке, если NULL не имеет значения, но я могу видеть аргументы для обоих. Если вы внимательно относитесь к кодированию, возможно, вы, возможно, устраните случайное обходное обращение, убедившись, что вы всегда передаете свои переменные по ссылке const, например:

myfunc( const_cast< const int& >( a ) );

// Alternatively, this approach may require additional handling 
// in the function, but it cleaner at call point
myfunc( boost::cref( a ) );

Тем не менее, много дополнительного кода для небольшой выгоды. Как заметил Кенни, С# обратился к этому с противоположного конца (требуя специальной передачи по ссылке), но это не вариант для С++ (если, например, вы не написали свои функции, чтобы взять ссылочную оболочку в качестве своего параметра, например boost:: ref (param)), например:

void myfunc( const boost::reference_wrapper< int >& a ) { ... }

Устранение проблемы с указателем является более проблематичным, хотя... нет способа компиляции, чтобы гарантировать, что указатель действителен, поэтому вы получаете либо проблемы времени выполнения для проблем указателя, либо проверку времени выполнения, либо и то, и другое. Такова природа указателей.

Во всяком случае, это только мое мнение, для чего это стоит.

Ответ 7

Что-то примечание, если вы используете stl-функторы, проще, если параметр соответствует типу значения контейнера.

void foo(Bar *);

void frobnicate(vector<Bar *> vecBars)
{
   for_each(vecBars.begin(), 
            vecBars.end(), 
            ptr_fun(&foo));
}

Приведенный выше код намного сложнее, если foo принимает Bar &

Ответ 8

В идеальном мире сводится к тому, является ли параметр дополнительным выходом. Вы хотите разрешить вызывающему абоненту передавать NULL, если они не заботятся об этом? Затем используйте указатель. В противном случае лучше выбрать ссылку.

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

Ответ 9

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

Еще одна вещь, о которой уже упоминалось, когда вы вызываете f(a,b), может возникнуть путаница, если вызывающий абонент не знает, что f может потенциально изменить значение для b

Однако еще одна проблема, которая довольно тонкая, но я все еще сталкивался с ней, является семантикой ссылок.

Указатели передаются по значению, но ссылки отсутствуют.

Это означает, что если вы передаете параметр по указателю, вы можете изменить указатель и указать на что-то еще.

Рассмотрим это:

void f1_ptr( type * a )
{
    a = new type(); //no change to passed parameters, you're changing the pointer which was passed by value
}

void f2_ptr( type * a )
{
    *a = some_other_value; //now you're changing the value of the parameter that was passed

   //or, if type is a class or struct:

   a->some_method_that_modifies_object(); //again, changing the parameter that was passed
}

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

void f3_ref( type& a )
{
    a = type(); //the referred variable has also changed
}

//....

type obj = type( params );

f3_ref( obj ); //obj now changed

f1_ptr( &obj ); //obj doesn't change

f2_ptr( &obj ); //obj now changed