186 votes

Pourquoi les tableaux de références sont-ils illégaux ?

Le code suivant ne compile pas.

int a = 1, b = 2, c = 3;
int& arr[] = {a,b,c,8};

Que dit la norme C++ à ce sujet ?

Je sais que je peux déclarer une classe qui contient une référence, puis créer un tableau de cette classe, comme indiqué ci-dessous. Mais je veux vraiment savoir pourquoi le code ci-dessus ne compile pas.

struct cintref
{
    cintref(const int & ref) : ref(ref) {}
    operator const int &() { return ref; }
private:
    const int & ref;
    void operator=(const cintref &);
};

int main() 
{
  int a=1,b=2,c=3;
  //typedef const int &  cintref;
  cintref arr[] = {a,b,c,8};
}

Il est possible d'utiliser struct cintref au lieu de const int & pour simuler un tableau de références.

1 votes

Même si le tableau était valide, y stocker une valeur brute de '8' ne fonctionnerait pas. Si vous faisiez "intlink value = 8 ;", cela mourrait horriblement, car cela se traduirait simplement par "const int & value = 8 ;". Une référence doit faire référence à une variable.

3 votes

intlink value = 8; Cela fonctionne. Vérifiez si vous n'y croyez pas.

7 votes

Comme le souligne Alexey, il est parfaitement valable de lier une rvalue à une référence const.

214voto

Kirill V. Lyadvinsky Points 47627

Pour répondre à votre question sur la norme, je peux citer la Norme C++ §8.3.2/4 :

Il n'y a pas de références à des références, pas de tableaux de références et aucun pointeur vers des références.

C'est parce que les références ne sont pas des objets et qu'elles n'occupent pas la mémoire et n'ont donc pas d'adresse. On peut les considérer comme des alias pour les objets. Déclarer un tableau de rien n'a pas beaucoup de sens.

45 votes

Qu'y a-t-il à dire de plus ?

21 votes

Il devrait y avoir des tableaux de références pour la même raison que nous avons des tableaux de pointeurs, même information mais manipulation différente, non ?

1 votes

La norme C++ dit : ** votre logique, laissez la nôtre !

72voto

Charles Bailey Points 244082

Les références ne sont pas des objets. Elles n'ont pas de stockage propre, elles ne font que référencer des objets existants. C'est pourquoi il n'est pas utile d'avoir des tableaux de références.

Si vous voulez un poids léger objet qui fait référence à un autre objet, vous pouvez utiliser un pointeur. Vous ne pourrez utiliser un struct avec un membre de référence en tant qu'objets dans des tableaux si vous fournissez une initialisation explicite pour tous les membres de référence pour tous les membres de référence. struct instances. Les références ne peuvent pas être mises en majuscules par défaut.

Editar: Comme le note jia3ep, dans la section standard sur les déclarations, il y a une interdiction explicite sur les tableaux de références.

11 votes

Les références sont de même nature que les pointeurs constants et, par conséquent, elles occupent de la mémoire (stockage) pour pointer vers quelque chose.

8 votes

Pas nécessairement. Le compilateur peut éviter de stocker l'adresse, si c'est une référence à un objet local par exemple.

5 votes

Pas nécessairement. Les références dans les structures occupent généralement de l'espace de stockage. Les références locales ne le font souvent pas. Quoi qu'il en soit, au sens strict du terme, les références ne sont pas des objets et (c'est nouveau pour moi) les références nommées ne sont pas réellement des objets. variables .

40voto

greggo Points 840

Il s'agit d'une discussion intéressante. Il est clair que les tableaux de références sont carrément illégaux, mais je pense que la raison n'est pas aussi simple que de dire "ce ne sont pas des objets" ou "ils n'ont pas de taille". J'aimerais souligner que les tableaux eux-mêmes ne sont pas des objets à part entière en C/C++ - si vous n'êtes pas d'accord avec cela, essayez d'instancier des classes de modèles stl en utilisant un tableau comme paramètre de modèle de 'classe', et voyez ce qui se passe. Vous ne pouvez pas les retourner, les assigner, les passer comme paramètres. (un paramètre de tableau est traité comme un pointeur). Mais il est légal de créer des tableaux de tableaux. Les références ont une taille que le compilateur peut et doit calculer - vous ne pouvez pas utiliser sizeof() pour une référence, mais vous pouvez créer une structure ne contenant que des références. Elle aura une taille suffisante pour contenir tous les pointeurs qui implémentent les références. Vous ne pouvez pas instancier une telle structure sans initialiser tous ses membres :

struct mys {
 int & a;
 int & b;
 int & c;
};
...
int ivar1, ivar2, arr[200];
mys my_refs = { ivar1, ivar2, arr[12] };

my_refs.a += 3  ;  // add 3 to ivar1

En fait, vous pouvez ajouter cette ligne à la définition de la structure

struct mys {
 ...
 int & operator[]( int i ) { return i==0?a : i==1? b : c; }
};

...et maintenant j'ai quelque chose qui ressemble BEAUCOUP à un tableau de refs :

int ivar1, ivar2, arr[200];
mys my_refs = { ivar1, ivar2, arr[12] };

my_refs[1] = my_refs[2]  ;  // copy arr[12] to ivar2
&my_refs[0];               // gives &my_refs.a == &ivar1

Maintenant, ce n'est pas un vrai tableau, c'est une surcharge d'opérateur ; il ne fera pas les choses que les tableaux font normalement comme sizeof(arr)/sizeof(arr[0]), par exemple. Mais il fait exactement ce que je veux qu'un tableau de références fasse, avec un C++ parfaitement légal. Sauf que (a) c'est une douleur à mettre en place pour plus de 3 ou 4 éléments, et (b) ça fait un calcul en utilisant un tas de ? : qui pourrait être fait en utilisant l'indexation (pas avec l'indexation normale de la sémantique de calcul des pointeurs en C, mais l'indexation quand même). J'aimerais voir un type 'tableau de références' très limité qui puisse réellement faire cela. C'est-à-dire qu'un tableau de références ne serait pas traité comme un tableau général de choses qui sont des références, mais plutôt comme un nouveau type de "tableau de référence" qui correspondrait effectivement à une classe générée en interne, similaire à celle ci-dessus (mais que vous pouvez malheureusement utiliser pour créer un tableau de référence). ne peut pas faire avec des modèles).

ceci pourrait probablement fonctionner, si vous n'êtes pas gêné par ce genre de choses : refondre '*this' en un tableau d'int * et retourner une référence faite à partir de l'un d'entre eux : (non recommandé, mais cela montre comment le bon 'tableau' fonctionnerait) :

 int & operator[]( int i ) { return *(reinterpret_cast<int**>(this)[i]); }

1 votes

Vous peut faire cela en C++11 std::tuple<int&,int&,int&> abcref = std::tie( a,b,c) - qui crée un "tableau" de références qui ne peut être indexé que par des constantes de compilation en utilisant std::get. Mais vous ne pouvez pas faire std::array<int&,3> abcrefarr = std::tie( a,b,c) . Il y a peut-être un moyen de le faire que je ne connais pas. Il me semble qu'il devrait y avoir un moyen d'écrire une spécialisation de std::array<T&,N> dont peut le faire - et donc une fonction std::tiearray(...) qui renvoie un tel (ou permet std::array<T&,N> pour accepter un initialisateur contenant des adresses = {&v1, &v2 etc})

1 votes

Votre proposition est stupide (IMO), et votre dernière ligne suppose qu'un int peut contenir un pointeur (généralement faux, au moins là où je travaille). Mais c'est la seule réponse ici avec un raisonnement légitime pour expliquer pourquoi les tableaux de références sont interdits, donc +1.

0 votes

@Nemo ce n'était pas vraiment prévu comme une proposition, mais juste pour illustrer que la fonctionnalité d'une telle chose n'est pas absurde à première vue. Je note dans mon dernier commentaire que le c++ a des choses qui s'en rapprochent. De plus, la dernière ligne à laquelle vous faites référence suppose que la mémoire qui implémente un fichier de type référence vers un int peut être utilement aliasé comme un pointeur vers un int -- la structure contient des références, pas des ints -- et cela tend à être vrai. Je ne prétends pas que c'est portable (ou même à l'abri des règles de "comportement indéfini"). Il s'agissait d'illustrer comment l'indexation pourrait être utilisée sous le capot pour éviter tous les problèmes de comportement. ?:

13voto

EFraim Points 7137

Un tableau est implicitement convertible en un pointeur, et Le pointeur à référence est illégal en C++.

11 votes

Il est vrai que vous ne pouvez pas avoir un pointeur sur une référence, mais ce n'est pas la raison pour laquelle vous ne pouvez pas avoir un tableau de références. Il s'agit plutôt de deux symptômes du fait que les références ne sont pas des objets.

3 votes

Une structure ne peut contenir que des références, et elle aura une taille proportionnelle à leur nombre. Si vous aviez un tableau de références 'arr', la conversion normale de tableau à pointeur n'aurait pas de sens, puisque 'pointeur à référence' n'a pas de sens. mais il serait logique d'utiliser simplement arr[i] , de la même manière que st.ref lorsque 'st' est une structure contenant une référence. Hmm. Mais &arr[0] donnerait l'adresse du premier objet référencé, et &arr[1]- &arr[0] ne serait pas la même chose que &arr[2]-&arr[1] - cela créerait beaucoup d'étrangeté.

10voto

navigator Points 1005

Parce que comme beaucoup l'ont dit ici, les références ne sont pas des objets, ce sont simplement des alias. Il est vrai que certains compilateurs peuvent les implémenter comme des pointeurs, mais la norme ne le spécifie pas. Et parce que les références ne sont pas des objets, vous ne pouvez pas pointer vers elles. Stocker des éléments dans un tableau signifie qu'il y a une sorte d'adresse d'index (c'est-à-dire pointer vers des éléments à un certain index) ; et c'est pourquoi vous ne pouvez pas avoir de tableaux de références, parce que vous ne pouvez pas pointer vers eux.

Utilisez boost::reference_wrapper, ou boost::tuple à la place ; ou simplement des pointeurs.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X