Какой из них лучше: Передать по ссылке с помощью void increment(int& x)
или же Пройти мимо указателя с помощью void increment(int* x)
?
void increment(int& x)
{
x=x+1;
}
int main()
{
int n= 2;
increment(n);
cout << "Value of n is " << n << '\n';
return 0;
}
или же
void increment(int* x)
{
*x=*x+1;
}
int main()
{
int n= 2;
increment(&n);
cout << "Value of n is " << n << '\n';
return 0;
}
Нет лучше. Преимущество использования указателя состоит в том, что в вызывающем коде явно указывается, что аргумент передается указателем, поскольку перед аргументом стоит &
, Преимущество использования ссылки в том, что она более естественна в коде вызывающей функции без *
разыменовывает. Внутренне они обычно реализуются таким же образом, поэтому не должно быть никаких преимуществ в скорости.
Не зная, что вы думаете «лучше», я могу только сказать, что они разные.
Плюсы прохождения по ссылке:
nullptr
и усложнит передачу неверного значения.С точки зрения производительности, вы не увидите большой разницы.
Плюсы прохождения по указателю:
Передача по ссылке не совместима с C, поэтому, если вы предоставляете функцию, которую вы ожидаете вызвать из C, вам нужно заставить ее передавать указатель.
Передача указателя позволяет вам пройти nullptr
/NULL
, Хотя перечисление этого преимущества может показаться противоречащим перечислению невозможности сделать это преимуществом ссылок, оно зависит от того, как вы используете свою функцию. если ты хочу чтобы можно было указать, что для параметра нет значения (и не нужно включать boost::optional
или сверните свое собственное), тогда указатель — идиоматический способ сделать это.
В этом конкретном случае я бы предпочел передавать по ссылке, поскольку нет причин вызывать функцию без допустимого значения.
Мое личное правило:
Так что в вашем случае, где функция increment()
Ясно изменить переданную переменную, я бы использовал указатель. Если вы используете ссылку, кто-то, читающий ваш код, должен будет перейти к объявлению функции, чтобы понять побочный эффект функции.
Для внешнего компонента (т. Е. При написании библиотеки потребляют третьи стороны), я бы взял указатель, он дает пользователям знать, что вы собираетесь изменить то, что они передают. Это происходит за счет разыменования указателя, которое имеет очень очень незначительные затраты производительности — так как вы захотите проверить указатель не NULL
перед его использованием.
Для внутренних функций, которые не предназначены для показа, предпочтительнее передавать по ссылке, так как это проще для записи и (опять же, очень незначительно) более производительно.
С лязгом и без оптимизаций:
00000000004004c0 <_Z10doThingRefRi>:
4004c0: 48 89 7c 24 f8 mov %rdi,-0x8(%rsp)
4004c5: 48 8b 7c 24 f8 mov -0x8(%rsp),%rdi
4004ca: 8b 07 mov (%rdi),%eax
4004cc: 05 01 00 00 00 add $0x1,%eax
4004d1: 89 07 mov %eax,(%rdi)
4004d3: c3 retq
4004d4: 66 66 66 2e 0f 1f 84 data32 data32 nopw %cs:0x0(%rax,%rax,1)
4004db: 00 00 00 00 00
00000000004004e0 <_Z10doThingPtrPi>:
4004e0: 48 89 7c 24 f8 mov %rdi,-0x8(%rsp)
4004e5: 48 81 7c 24 f8 00 00 cmpq $0x0,-0x8(%rsp)
4004ec: 00 00
4004ee: 0f 84 0f 00 00 00 je 400503 <_Z10doThingPtrPi+0x23>
4004f4: 48 8b 44 24 f8 mov -0x8(%rsp),%rax
4004f9: 8b 08 mov (%rax),%ecx
4004fb: 81 c1 01 00 00 00 add $0x1,%ecx
400501: 89 08 mov %ecx,(%rax)
400503: c3 retq
400504: 66 66 66 2e 0f 1f 84 data32 data32 nopw %cs:0x0(%rax,%rax,1)
40050b: 00 00 00 00 00
с лязгом и -O3
00000000004004c0 <_Z10doThingRefRi>:
4004c0: ff 07 incl (%rdi)
4004c2: c3 retq
4004c3: 66 66 66 66 2e 0f 1f data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)
4004ca: 84 00 00 00 00 00
00000000004004d0 <_Z10doThingPtrPi>:
4004d0: 48 85 ff test %rdi,%rdi
4004d3: 74 02 je 4004d7 <_Z10doThingPtrPi+0x7>
4004d5: ff 07 incl (%rdi)
4004d7: c3 retq
4004d8: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
4004df: 00