Что означает `* &` в объявлении функции? - PullRequest
20 голосов
/ 15 сентября 2009

Я написал такую ​​функцию:

void myFunc(myStruct *&out) {
    out = new myStruct;
    out->field1 = 1;
    out->field2 = 2;
}

Теперь в вызывающей функции я мог бы написать что-то вроде этого:

myStruct *data;
myFunc(data);

, который заполнит все поля в data. Если я опущу '&' в объявлении, это не будет работать. (Вернее, он будет работать только локально в функции, но ничего не изменит в вызывающей программе)

Может ли кто-нибудь объяснить мне, что на самом деле делает этот '*&'? Это выглядит странно, и я просто не могу понять это.

Ответы [ 9 ]

36 голосов
/ 15 сентября 2009

Символ & в объявлении переменной C ++ означает, что это ссылка .

Это ссылка на указатель, которая объясняет семантику, которую вы видите; вызываемая функция может изменить указатель в вызывающем контексте, так как она имеет ссылку на него.

Итак, повторюсь, «действующий символ» здесь не *&, эта комбинация сама по себе не значит много. * является частью типа myStruct *, то есть "указатель на myStruct", а & делает его ссылкой, поэтому вы должны прочитать его как "out - ссылка на указатель myStruct».

Первоначальный программист мог бы помочь, на мой взгляд, написав его так:

void myFunc(myStruct * &out)

или даже (не в моем личном стиле, но, конечно, все еще в силе):

void myFunc(myStruct* &out)

Конечно, есть много других мнений о стиле. :)

13 голосов
/ 15 сентября 2009

В C и C ++ & означает вызов по ссылке; Вы разрешаете функции изменять переменную. В этом случае ваша переменная является указателем на тип myStruct. В этом случае функция выделяет новый блок памяти и присваивает это указателю «данные».

В прошлом (скажем, K & R) это нужно было делать, передавая указатель, в данном случае указатель на указатель или **. Оператор ссылки обеспечивает более читаемый код и более строгую проверку типов.

6 голосов
/ 15 сентября 2009

Возможно, стоит объяснить, почему это не &*, а наоборот. Причина в том, что объявления создаются рекурсивно, и поэтому ссылка на указатель создается как

& out // reference to ...
* (& out) // reference to pointer

Скобки опущены, так как они избыточны, но они могут помочь вам увидеть шаблон. (Чтобы понять, почему они избыточны, представьте, как это выглядит в выражениях, и вы заметите, что сначала берется адрес, а затем разыменовывается - это тот порядок, который мы хотим и что скобки не изменятся). Если вы измените заказ, вы получите

* out // pointer to ...
& (* out) // pointer to reference

Указатель на ссылку недопустим. Вот почему заказ *&, что означает «ссылка на указатель».

6 голосов
/ 15 сентября 2009

Похоже, вы заново реализуете конструктор!

Почему бы просто не создать соответствующий конструктор?
Обратите внимание, что в C ++ структура похожа на класс (может иметь конструктор)

struct myStruct
{
    myStruct()
        :field1(1)
        ,field2(2)
    {}
};

myStruct*  data1 = new myStruct;

// or Preferably use a smart pointer
std::auto_ptr<myStruct>   data2(new myStruct);

// or a normal object
myStruct    data3;
3 голосов
/ 17 сентября 2009

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

void myFunc(myStruct *out);

Что произойдет, если вашей функции будет передана копия указателя для работы. Это означает, что указатель будет указывать на одну и ту же вещь, но будет другой переменной. Здесь любые изменения, сделанные в *out (то есть на какие точки), будут постоянными, но изменения, внесенные в out (сам указатель), будут применяться только внутри myFunc. С такой подписью

void myFunc(myStruct *&out);

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

Как говорится, линия

out = new myStruct;

изменяет указатель переменной out, а не *out. На что бы out ни указывал, он все еще жив и здоров, но теперь в куче создан новый экземпляр myStruct, и out был изменен, чтобы указывать на него.

3 голосов
/ 15 сентября 2009

В C ++ это ссылка на указатель, своего рода эквивалент указателя на указатель в C, поэтому аргумент функции можно назначить.

2 голосов
/ 15 сентября 2009

Как и в большинстве типов данных в C ++, вы можете читать их справа налево, и это будет иметь смысл.

myStruct *&out

out является ссылкой (&) на указатель (*) на myStruct объект. Это должна быть ссылка, поскольку вы хотите изменить то, на что указывает out (в данном случае new myStruct).

2 голосов
/ 15 сентября 2009
1 голос
/ 15 сентября 2009

MyClass * & MyObject

Здесь MyObject является ссылкой на указатель MyClass. Таким образом, вызов myFunction (MyClass * & MyObject) является вызовом по ссылке, мы можем изменить MyObject, который является ссылкой на указатель. Но если мы сделаем myFunction (MyClass * MyObject), мы не сможем изменить MyObject, потому что это вызов по значению, он просто скопирует адрес во временную переменную, чтобы мы могли изменить значение, где MyObject является Pointing, но не MyObject.

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

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