web-dev-qa-db-fra.com

Qu'est-ce que `* &` dans une déclaration de fonction signifie?

J'ai écrit une fonction dans les lignes de ceci:

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

Maintenant, dans une fonction d'appel, je pourrais écrire quelque chose comme ceci:

myStruct *data;
myFunc(data);

qui remplira tous les champs de data. Si j'étant _ & 'Dans la déclaration, cela ne fonctionnera pas. (Ou plutôt, cela ne fonctionnera que localement dans la fonction mais ne changera rien dans l'appelant)

Est-ce que quelqu'un pourrait m'expliquer ce que ça "*& 'réellement? Il a l'air bizarre et je ne peux tout simplement pas faire beaucoup de sens.

21
bastibe

Le symbole et le symbole dans une déclaration de variable C++ signifie qu'il est un référence .

Il s'agit d'une référence à un pointeur, ce qui explique la sémantique que vous voyez; La fonction appelée peut modifier le pointeur dans le contexte d'appel, car il y en a une référence.

Donc, pour réitérer, le "symbole opératoire" ici n'est pas *&, cette combinaison en elle-même ne signifie pas beaucoup beaucoup. Les * fait partie du type myStruct *, c'est-à-dire "" pointeur à myStruct ", et le & en fait une référence, vous le liriez donc "out est une référence à un pointeur à myStruct".

Le programmeur d'origine aurait pu aider, à mon avis, en l'écrivant comme suit:

void myFunc(myStruct * &out)

ou même (pas mon style personnel, mais bien sûr toujours valable):

void myFunc(myStruct* &out)

Bien sûr, il y a beaucoup d'autres opinions sur le style. :)

37
unwind

En C et C++, et signifie appeler par référence; Vous autorisez la fonction de modifier la variable. Dans ce cas, votre variable est un pointeur de type muntructeur. Dans ce cas, la fonction attribue un nouveau bloc de mémoire et l'attribue à votre pointeur 'Data'.

Dans le passé (dire K & R), cela devait être fait en passant un pointeur, dans ce cas un pointeur à pointeur ou **. L'opérateur de référence permet un code plus lisible et une vérification de type plus forte.

13
Adriaan

Cela semble que vous réémayez un constructeur!

Pourquoi ne pas simplement créer le constructeur approprié?
Remarque en C++ une structure est comme une classe (il peut avoir un constructeur).

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;
6
Martin York

Il peut être utile d'expliquer pourquoi ce n'est pas &*, mais l'inverse. La raison en est que les déclarations sont construites de manière récursive et une référence à un pointeur s'accumule comme

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

Les parenthèses sont larguées car elles sont redondantes, mais elles peuvent vous aider à voir le modèle. (Pour voir pourquoi ils sont redondants, imaginez comment la chose ressemble dans les expressions et vous remarquerez d'abord que l'adresse est prise, puis déréférencée - c'est l'ordre que nous voulons et que les parenthèses ne changent pas). Si vous changez de la commande, vous obtiendrez

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

Le pointeur sur référence n'est pas légal. C'est pourquoi l'ordre est *&, ce qui signifie "référence au pointeur".

6

En C++, il s'agit d'une référence à un pointeur, en quelque sorte équivalent à un pointeur au pointeur en C, l'argument de la fonction est donc assigné.

3
Nikolai Fetissov

Comme les autres l'ont dit, les & moyens vous font référence à la variable réelle dans la fonction, par opposition à une copie. Cela signifie que toute modification apportée à la variable dans la fonction affecte la variable d'origine. Cela peut être particulièrement déroutant lorsque vous passez un pointeur, qui est déjà une référence à autre chose. Dans le cas où votre signature de fonction ressemblait à ceci

void myFunc(myStruct *out);

Ce qui se passerait-il, c'est que votre fonction serait adoptée une copie du pointeur pour travailler. Cela signifie que le pointeur pointerait à la même chose, mais serait une variable différente. Ici, toute modification apportée à *out (c'est-à-dire quels points de sortie) serait permanent, mais les modifications apportées à out (le pointeur lui-même) ne s'appliquerait qu'à l'intérieur de myFunc. Avec la signature comme celle-ci

void myFunc(myStruct *&out);

Vous déclarez que la fonction prendra une référence au pointeur d'origine. Maintenant, toute modification apportée à la variable du pointeur out va affecter le pointeur d'origine qui a été transmis.

Cela étant dit, la ligne

out = new myStruct;

modifie la variable du pointeur out et non *out. Quoi que ce soit out _ _ utilisé pour pointer est toujours en vie et bien, mais maintenant une nouvelle instance de muntructeur a été créée sur le tas, et out a été modifié pour le pointer.

3
Graphics Noob
2
qrdl

Comme avec la plupart des types de données en C++, vous pouvez le lire à droite et il aura un sens.

myStruct *&out

out est une référence (&) à un pointeur (*) à un objet myStruct. Ce doit être une référence parce que vous souhaitez modifier ce que out points à (dans ce cas, un new myStruct).

2
Michael Kristofik

MyClass * & myObject

Ici MyObject fait référence à un pointeur de MyClass. Ainsi, appeler la mycée (MyClass * & MyObject) est appelé par référence, nous pouvons changer MyObject, qui fait référence à un pointeur. Mais si nous faisons mycoscincice (myClass * MyObject), nous ne pouvons pas changer MyObject car il est appelé par valeur, il suffira de copier l'adresse dans une variable temporaire afin de pouvoir modifier la valeur où MyObject pointe, mais pas de MyObject.

donc, dans ce cas, l'écrivain est d'abord attribuer une nouvelle valeur à celle-ci, pourquoi appeler par référence est nécessaire.

1
GG.