Передача объекта в качестве ссылки или указателя в функцию - PullRequest
3 голосов
/ 01 декабря 2011

Я знаю, что вопрос «когда указатель и когда ссылка» или «передать аргумент в функцию по ссылке или передать по указателю» задавался много раз.Однако у меня сложилось впечатление, что в некоторых случаях я читал: «Вы должны передавать объект в функцию по указателю, когда вы хотите изменить его».Может ли кто-то сказать, объяснить и оправдать, если последнее предложение является полностью правильным?

Или, другими словами, нельзя ли изменить объект с помощью ссылки?

Ответы [ 6 ]

4 голосов
/ 01 декабря 2011

Для удобства я буду ссылаться на параметр, который изменяется функцией как «out-param».

Out-params можно передавать как неконстантные ссылки. Там нет технической причины не делать этого. Например, в стандартных библиотеках std::swap принимает два параметра по ссылке и изменяет оба.

В прошлом я видел, как правило, в руководстве по стилю, что выходные параметры должны передаваться по указателю, а не по ссылке. Мотивация этого заключается в том, что некоторые люди [*] хотят, чтобы вызов функции появлялся , чтобы передать объект по значению, чтобы оставить объект неизмененным. Это позволяет им рассуждать о куске кода, просто взглянув на вызывающий код, без необходимости искать то, что на самом деле делает функция. Например:

int foo(int a) {
    return a + 1;
}
int bar(int &a) {
    return ++a;
}

Теперь, учитывая int i = 0;, вызовы foo(i) и bar(i) выглядят абсолютно одинаково, но один из них ведет себя как хорошая, простая функция C, тогда как другой использует для передачи * 1015 передачу по ссылке *.

Некоторые люди [*] хотят, чтобы эти разные вещи явно отличались на сайте вызовов, поэтому они предпочли бы написать bar(&i), чтобы дать понять, что i можно изменить [**]. По сути, они предпочли бы, чтобы в C ++ вообще не было неконстантных ссылок в качестве параметров функции.

Не обязательно что-то плохое в том, что эти люди хотят сделать. Например, вы можете придерживаться его в случае std::swap, всегда используя вместо него std::iter_swap. Но большинство руководств по стилю C ++ не имеют такого правила.

[*] например, программисты на C

[**] Фактически, в моей функции bar, a является одновременно входным и выходным параметром. Их предпочтительная функция int bar(int *pa); технически не имеет внешнего параметра, хотя для удобства они, вероятно, будут ссылаться на референд pa (то есть i) как на дополнительный параметр, и каждый знает, что это значит .

4 голосов
/ 01 декабря 2011

Вы должны передать объект как двойной указатель, если вы хотите изменить то, на что указывает указатель, например, при перемещении объекта из одной ячейки памяти в другую:

void foo (obj **x) {
  delete *x;
  obj *y = (obj *) some_new_address;
  *x = y; // change what x points to
}
...
obj *x = new obj();
foo(&obj);
// obj now points to another location

С помощью ссылки вы можетене делай этого.

2 голосов
/ 01 декабря 2011

Предложение, которое вы цитируете, является нормативным, то есть оно говорит вам, что вы «должны» делать, а не то, что «можете» или «не можете» делать. Таким образом, это вопрос стиля и предмет споров. Я лично не принимаю это.

Конечно, можно изменить объект с помощью (не const) ссылки.

1 голос
/ 01 декабря 2011

Конечно, можно изменить объект через ссылку.Может быть, предложение, которое вы процитировали, было о C, на который нет ссылок?

Инструкция примерно такая:

  • Если вы хотите изменить аргумент, а вызывающий может его не предоставить, передайтепо указателю (и передайте NULL, 0 или nullptr без объекта).
  • Если вы хотите изменить аргумент и объект должен быть передан функции - передайте по ссылке.
  • Если вы не хотите изменять аргумент, но вызывающая сторона не может его предоставить, передайте по константному указателю
  • В противном случае, если объект дорого копировать, передайте по константной ссылке, если нет, передайте по значению.
  • Новая функция - если вы хотите скопировать аргумент внутри функции (например, передать строку в конструктор для инициализации поля) и используете компилятор, совместимый с C ++ 11 (поддержка конструкторов перемещения), передайте по значению.
0 голосов
/ 01 декабря 2011

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

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

0 голосов
/ 01 декабря 2011

вы можете изменить ваш объект как по ссылке, так и по указателю.Если вы не хотите изменять, вы можете использовать модификатор const.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...