Array declaration
Déclare un objet de type tableau.
Table des matières |
Syntaxe
Une déclaration de tableau est toute déclaration simple dont le déclarateur a la forme
noptr-declarator
[
expr
(optionnel)
]
attr
(optionnel)
|
|||||||||
| noptr-declarator | - |
tout
declarator
valide, mais s'il commence par
*
,
&
, ou
&&
, il doit être entouré de parenthèses (sinon l'ensemble du déclarateur est traité comme un
pointeur déclarator
ou
référence déclarator
).
|
| expr | - | une expression constante entière (jusqu'en C++14) une expression constante convertie de type std::size_t (depuis C++14) , qui s'évalue à une valeur supérieure à zéro |
| attr | - | (depuis C++11) liste d' attributs |
Une déclaration de la forme
T a
[
N
]
;
, déclare
a
comme un
objet
tableau constitué de
N
objets de type
T
alloués de manière contiguë. Les éléments d'un tableau sont numérotés
0
, …,
N
-
1
, et peuvent être accédés avec l'
opérateur d'indice []
, comme dans
a
[
0
]
, …,
a
[
N
-
1
]
.
Les tableaux peuvent être construits à partir de tout type fondamental (sauf void ), pointeurs , pointeurs vers membres , classes , énumérations , ou à partir d'autres tableaux de taille connue (auquel cas le tableau est dit multidimensionnel). En d'autres termes, seuls les types objets à l'exception des types tableaux de taille inconnue peuvent être des types d'éléments de types tableaux. Les types tableaux de type d'élément incomplet sont également des types incomplets.
|
Le spécificateur
éventuellement
contraint
(depuis C++20)
|
(depuis C++11) |
Il n'y a pas de tableaux de références ni de tableaux de fonctions.
L'application de cv-qualifiers à un type tableau (via typedef ou manipulation de type template) applique les qualificateurs au type élément, mais tout type tableau dont les éléments sont de type cv-qualifié est considéré comme ayant la même qualification cv.
// a et b ont le même type qualifié const "tableau de 5 const char" typedef const char CC; CC a[5] = {}; typedef char CA[5]; const CA b = {};
Lorsqu'il est utilisé avec une new[]-expression , la taille d'un tableau peut être zéro ; un tel tableau n'a aucun élément :
int* p = new int[0]; // l'accès à p[0] ou *p est indéfini delete[] p; // le nettoyage reste nécessaire
Affectation
Les objets de type tableau ne peuvent pas être modifiés dans leur ensemble : bien qu'ils soient des lvalues (par exemple, l'adresse d'un tableau peut être prise), ils ne peuvent pas apparaître à gauche d'un opérateur d'assignation :
int a[3] = {1, 2, 3}, b[3] = {4, 5, 6}; int (*p)[3] = &a; // correct : l'adresse de a peut être prise a = b; // erreur : a est un tableau struct { int c[3]; } s1, s2 = {3, 4, 5}; s1 = s2; // correct : l'opérateur d'affectation de copie défini implicitement // peut affecter les membres de données de type tableau
Dégénérescence tableau-vers-pointeur
Il y a une conversion implicite des lvalues et rvalues de type tableau vers des rvalues de type pointeur : elle construit un pointeur vers le premier élément d'un tableau. Cette conversion est utilisée chaque fois que des tableaux apparaissent dans un contexte où des tableaux ne sont pas attendus, mais des pointeurs le sont :
#include <iostream> #include <iterator> #include <numeric> void g(int (&a)[3]) { std::cout << a[0] << '\n'; } void f(int* p) { std::cout << *p << '\n'; } int main() { int a[3] = {1, 2, 3}; int* p = a; std::cout << sizeof a << '\n' // affiche la taille du tableau << sizeof p << '\n'; // affiche la taille d'un pointeur // là où les tableaux sont acceptables mais pas les pointeurs, seuls les tableaux peuvent être utilisés g(a); // correct : la fonction prend un tableau par référence // g(p); // erreur for (int n : a) // correct : les tableaux peuvent être utilisés dans les boucles range-for std::cout << n << ' '; // affiche les éléments du tableau // for (int n : p) // erreur // std::cout << n << ' '; std::iota(std::begin(a), std::end(a), 7); // correct : begin et end prennent des tableaux // std::iota(std::begin(p), std::end(p), 7); // erreur // là où les pointeurs sont acceptables mais pas les tableaux, les deux peuvent être utilisés : f(a); // correct : la fonction prend un pointeur f(p); // correct : la fonction prend un pointeur std::cout << *a << '\n' // affiche le premier élément << *p << '\n' // idem << *(a + 1) << ' ' << a[1] << '\n' // affiche le deuxième élément << *(p + 1) << ' ' << p[1] << '\n'; // idem }
Tableaux multidimensionnels
Lorsque le type d'élément d'un tableau est un autre tableau, on dit que le tableau est multidimensionnel :
// tableau de 2 tableaux de 3 entiers chacun int a[2][3] = {{1, 2, 3}, // peut être vu comme une matrice 2 × 3 {4, 5, 6}}; // avec un agencement row-major
Notez que lorsque la conversion tableau-vers-pointeur est appliquée, un tableau multidimensionnel est converti en un pointeur vers son premier élément (par exemple, un pointeur vers sa première ligne ou vers son premier plan) : la conversion tableau-vers-pointeur n'est appliquée qu'une seule fois.
int a[2]; // tableau de 2 int int* p1 = a; // a se dégrade en un pointeur vers le premier élément de a int b[2][3]; // tableau de 2 tableaux de 3 int // int** p2 = b; // erreur : b ne se dégrade pas en int** int (*p2)[3] = b; // b se dégrade en un pointeur vers la première ligne à 3 éléments de b int c[2][3][4]; // tableau de 2 tableaux de 3 tableaux de 4 int // int*** p3 = c; // erreur : c ne se dégrade pas en int*** int (*p3)[3][4] = c; // c se dégrade en un pointeur vers le premier plan 3 × 4 éléments de c
Tableaux de taille inconnue
Si expr est omis dans la déclaration d'un tableau, le type déclaré est "tableau de taille inconnue de T", qui est un type de type incomplet , sauf lorsqu'il est utilisé dans une déclaration avec un initialiseur agrégé :
extern int x[]; // le type de x est "tableau de taille inconnue d'entiers" int a[] = {1, 2, 3}; // le type de a est "tableau de 3 entiers"
Parce que les éléments de tableau ne peuvent pas être des tableaux de taille inconnue, les tableaux multidimensionnels ne peuvent pas avoir de taille inconnue dans une dimension autre que la première :
extern int a[][2]; // correct : tableau de taille inconnue de tableaux de 2 int extern int b[2][]; // erreur : le tableau a un type d'élément incomplet
S'il existe une déclaration précédente de l'entité dans la même portée où la dimension a été spécifiée, une dimension de tableau omise est considérée comme identique à celle de cette déclaration antérieure, et de même pour la définition d'un membre de données statique d'une classe :
extern int x[10]; struct S { static int y[10]; }; int x[]; // OK : limite est 10 int S::y[]; // OK : limite est 10 void f() { extern int x[]; int i = sizeof(x); // erreur : type d'objet incomplet }
Les références et les pointeurs vers des tableaux de taille inconnue peuvent être formés, mais ne peuvent pas (jusqu'au C++20) et peuvent (depuis C++20) être initialisés ou assignés à partir de tableaux et de pointeurs vers des tableaux de taille connue. Notez que dans le langage de programmation C, les pointeurs vers des tableaux de taille inconnue sont compatibles avec les pointeurs vers des tableaux de taille connue et sont donc convertibles et assignables dans les deux directions.
extern int a1[]; int (&r1)[] = a1; // correct int (*p1)[] = &a1; // correct int (*q)[2] = &a1; // erreur (mais correct en C) int a2[] = {1, 2, 3}; int (&r2)[] = a2; // correct (depuis C++20) int (*p2)[] = &a2; // correct (depuis C++20)
Les pointeurs vers des tableaux de taille inconnue ne peuvent pas participer aux opérations arithmétiques sur les pointeurs et ne peuvent pas être utilisés à gauche de l' opérateur d'indice , mais peuvent être déréférencés.
Rvalues de tableau
Bien que les tableaux ne puissent pas être retournés par valeur depuis des fonctions et ne puissent pas être la cible de la plupart des expressions de cast, des prvalues de tableau peuvent être formés en utilisant un alias de type pour construire un tableau temporaire via une conversion fonctionnelle avec initialisation par accolades .
|
Comme les prvalues de classe, les prvalues de tableau se convertissent en xvalues par matérialisation temporaire lors de l'évaluation. |
(depuis C++17) |
Les tableaux xvalues peuvent être formés directement en accédant à un membre tableau d'un rvalue de classe ou en utilisant std::move ou un autre cast ou appel de fonction qui retourne une référence à un rvalue.
#include <iostream> #include <type_traits> #include <utility> void f(int (&&x)[2][3]) { std::cout << sizeof x << '\n'; } struct X { int i[2][3]; } x; template<typename T> using identity = T; int main() { std::cout << sizeof X().i << '\n'; // taille du tableau f(X().i); // correct : se lie à une xvalue // f(x.i); // erreur : ne peut pas se lier à une lvalue int a[2][3]; f(std::move(a)); // correct : se lie à une xvalue using arr_t = int[2][3]; f(arr_t{}); // correct : se lie à une prvalue f(identity<int[][3]>{{1, 2, 3}, {4, 5, 6}}); // correct : se lie à une prvalue }
Sortie :
24 24 24 24 24
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Appliqué à | Comportement publié | Comportement correct |
|---|---|---|---|
| CWG 393 | C++98 |
un pointeur ou une référence vers un tableau de taille
inconnue ne pouvait pas être un paramètre de fonction |
autorisé |
| CWG 619 | C++98 |
lorsqu'omise, la taille d'un tableau ne pouvait
pas être déduite d'une déclaration précédente |
déduction autorisée |
| CWG 2099 | C++98 |
la taille d'un membre de données statique de type tableau
ne pouvait pas être omise même si un initialiseur est fourni |
omission autorisée |
| CWG 2397 | C++11 | auto ne pouvait pas être utilisé comme type d'élément | autorisé |
Voir aussi
|
Documentation C
pour
Déclaration de tableau
|