Tableaux ouverts

De RAD Studio
Aller à : navigation, rechercher

Remonter à Gestion des types de données et des concepts du langage Delphi


Prise en charge des tableaux ouverts

Object Pascal comporte une construction "tableau ouvert" qui permet de transmettre un tableau de taille indéterminée à une fonction. Bien qu'il n'y ait pas d'équivalent direct de ce type dans C++, il est possible d'appeler une fonction Object Pascal qui attend un paramètre tableau ouvert en lui transmettant explicitement deux paramètres :

  • Un pointeur sur le premier élément du tableau
  • Un paramètre count, qui est la valeur du dernier index (c'est-à-dire, la taille/le nombre d'éléments du tableau moins un)
Remarque : Le paramètre count était auparavant suivi du suffixe _Size, mais désormais il est précédé du suffixe _High, qui est équivalent à _Size moins 1.

Par exemple, la fonction Mean de math.hpp comporte les déclarations suivantes en Object Pascal et en C++ :

Déclaration Delphi :

 function  Mean(Data:  array of  Double): Double;

Déclaration C++ :

  double __fastcall Mean(double *Data, const int Data_High);

Le code suivant illustre l'appel de la fonction Mean en C++ :

 double  d[] = { 3.1, 4.4, 5.6 }; 
 
 // explicitly specifying last index 
 double  x = Mean(d, 2) ; 
 
 // better: use sizeof to ensure that the correct value is passed 
 double  y = Mean(d, ( sizeof (d) /  sizeof (d[0])) - 1) ; 
 
 // use macro in sysopen.h 
 double  z = Mean(d, ARRAYSIZE(d) - 1) ;

Remarque : Dans des cas similaires à cet exemple mais dans lesquels la fonction Object Pascal attend un paramètre var, la déclaration des paramètres de la fonction en C++ ne serait pas const.

Calcul du nombre d'éléments

Quand vous utilisez sizeof(), la macro ARRAYSIZE ou la macro EXISTINGARRAY pour calculer le nombre d'éléments d'un tableau, faites attention à ne pas utiliser à la place un pointeur sur le premier élément du tableau. Il faut transmettre à la place le nom d'un tableau.

double  d[] = { 3.1, 4.4, 5.6 } ; 
int  n = ARRAYSIZE(d); //  sizeof (d)/ sizeof (d[0]) => 24/8 =>  3 

double  *pd = d; 
int  m = ARRAYSIZE(pd); //  sizeof (pd)/ sizeof (pd[0]) => 4/8 => 0 => Error !

Utiliser la taille d'un tableau (avec "sizeof") ne revient pas au même que d'utiliser la taille d'un pointeur (avec "sizeof"). Par exemple, étant donné les déclarations suivantes :

double  d[3]; 
double  *p = d;

Utiliser la taille du tableau comme suit :

sizeof (d) / sizeof  d[0]

ne donne pas le même résultat que la taille du pointeur :

sizeof (p) / sizeof (p[0])

Cet exemple et ceux qui suivent utilisent la macro ARRAYSIZE à la place de l'opérateur sizeof(). Pour plus d'informations sur la macro ARRAYSIZE, voir l'aide en ligne.

Temporaires

Object Pascal gère le transfert de tableaux ouverts temporaires sans nom à des fonctions. Il n'y a pas de syntaxe équivalente en C++. Cependant comme des définitions de variable peuvent être mélangées à d'autres instructions, une approche consiste à fournir la variable avec un nom.

Delphi :

 Result := Mean([3.1, 4.4, 5.6]);

C++, en utilisant une variable "temporaire" nommée :

 double  d[] = { 3.1, 4.4, 5.6 } ; 
 return  Mean(d, ARRAYSIZE(d) - 1) ;

Pour limiter la portée de la variable "temporaire" nommée et éviter des conflits avec des variables locales, il suffit de créer sur place une nouvelle portée :

 long double  x; 
 
 { 
 double  d[] = { 4.4, 333.1, 0.0 } ; 
 x = Mean(d, ARRAYSIZE(d) - 1) ; 
 
 }

Pour une autre solution, voir la macro OPENARRAY.

array of const

Object Pascal gère une construction de langage appelée array of const. Ce type d'argument revient à utiliser par valeur un tableau ouvert de TVarRec.

Le segment de code suivant déclare en Object Pascal une fonction attendant un array of const :

function  Format( const  Format:  string ; Args:  array of const ):  string ;

En C++, le prototype est :

UnicodeString  __fastcall  Format( const  UnicodeString Format , 
TVarRec  const  *Args,  const int  Args_Size) ;

La fonction est appelée comme n'importe quelle fonction attendant un tableau ouvert :

void show_error ( int  error_code, UnicodeString  const  &error_msg) 
{ 
  TVarRec v[] = { error_code, error_msg } ; 
  ShowMessage(Format("%d: %s", v, ARRAYSIZE(v) - 1)) ; 
}

Macro OPENARRAY

La macro OPENARRAY définie dans sysopen.h peut être également utilisée au lieu de définir une variable nommée pour transmettre un tableau ouvert temporaire à une fonction qui attend un tableau ouvert transféré par valeur.

Cette macro s'utilise de la manière suivante :

OPENARRAY(T, (value1, value2, value3)) // up to 19 values

Où T est le type du tableau ouvert à construire, les paramètres value servant à remplir le tableau. Les parenthèses autour des paramètres value sont obligatoires. Par exemple :

void  show_error(int  error_code, UnicodeString  const  &error_msg) 
{
  ShowMessage(Format("%d: %s", OPENARRAY(TVarRec, (error_code, error_msg)))); 
}

Il est possible de transmettre jusqu'à 19 valeurs en utilisant la macro OPENARRAY. Si un tableau plus important est nécessaire, il faut définir une variable explicite. De plus, l'utilisation de la macro OPENARRAY entraîne un certain coût (mais faible) à l'exécution en raison de l'allocation du tableau sous-jacent et d'une copie supplémentaire de chaque valeur.

Exemples de code

Macro EXISTINGARRAY

La macro EXISTINGARRAY définie dans sysopen.h peut être utilisée pour transmettre un tableau existant quand un tableau ouvert est attendu.

Cette macro s'utilise de la manière suivante :

 long double  Mean( const double  *Data,  const int  Data_Size) ; 
 double  d[] = { 3.1, 3.14159, 2.17128 } ; 
 Mean(EXISTINGARRAY (d)) ;

Remarque : La section Calcul du nombre d'éléments s'applique aussi à la macro EXISTINGARRAY.

Fonctions C++ attendant un argument tableau ouvert

Quand vous écrivez une fonction C++ qui reçoit un tableau ouvert d'Object Pascal, il est important de gérer explicitement la sémantique "transfert par valeur". En particulier, si la déclaration de la fonction correspond à un "transfert par valeur", assurez-vous de copier explicitement chaque élément avant de les modifier. En Object Pascal, un tableau ouvert est un type prédéfini et peut être transmis par valeur. En C++, le type tableau ouvert étant implémenté en utilisant un pointeur, il est donc possible de modifier le tableau original sauf si vous en faites une copie.

Fonctions Object Pascal renvoyant des tableaux

Object Pascal permet aux fonctions de renvoyer des tableaux, mais C++ ne le permet pas. Pour rapprocher cette différence, les méthodes Object Pascal qui renvoient des tableaux (par exemple, T[1..n]) sont prototypées en renvoyant une instance de StaticArray<T, n>.

Voir aussi