58 votes

Pourquoi ne pouvons-nous pas passer des tableaux à la fonction par valeur ?

Apparemment, nous pouvons passer des instances de classes complexes aux fonctions, mais pourquoi ne pouvons-nous pas passer des tableaux aux fonctions ?

3 votes

Pour information, cela vient du C et comme les tableaux (les primitifs, pas les std::vector o std::array ) a été transposé dans le C++ pratiquement sans changement, je soupçonne que la raison est la même.

0 votes

@delnan, la raison est la même ? quelle est la "même" raison ? Veuillez être plus précis.

0 votes

Je crois que vous pouvez le faire avec boost::array (ou tr1::array).

71voto

Let_Me_Be Points 16797

L'origine est historique. Le problème est que la règle "les tableaux se décomposent en pointeurs, lorsqu'ils sont passés à une fonction" est simple.

Copier des tableaux serait un peu compliqué et pas très clair, puisque le comportement changerait pour différents paramètres et différentes déclarations de fonctions.

Notez que vous pouvez toujours faire une passe indirecte par valeur :

struct A { int arr[2]; };
void func(struct A);

3 votes

En C++, vous pouvez transmettre des tableaux aux fonctions par référence. Grâce aux modèles de fonctions et aux arguments de modèles non typés, vous pouvez même transmettre des tableaux de longueur arbitraire.

7 votes

La règle selon laquelle l'expression des tableaux se décompose en pointeurs n'est pas spécifique aux appels de fonction. En C, la désintégration se produit dans tout contexte autre que (a) l'opérande de la fonction unaire & (b) l'opérande de l'opérateur unitaire sizeof ou (c) un littéral de chaîne dans un initialisateur utilisé pour initialiser un tableau de caractères ( char s[] = "hello"; ) ; je pense qu'il existe une ou deux autres exceptions en C++, impliquant probablement des références. Par exemple, dans int arr[10]; int *p; p = arr; la décomposition se produit, mais il n'y a pas d'appel de fonction en vue.

1 votes

Cela n'explique pas du tout l'état actuel des choses. Il n'y a aucun problème à rendre les tableaux copiables et à se débarrasser de la désintégration implicite bizarre en pointeur. Cependant, cela nécessiterait probablement l'introduction d'une syntaxe spéciale pour convertir un tableau en pointeur (comme @arr ) exprimant l'intention d'obtenir un pointeur sur tous les éléments plutôt que sur le premier élément ( &(arr[0]) ), mais tous les symboles d'opérateur étaient déjà utilisés. Ou simplement leur base de code de l'époque ne nécessitait pas de copie de tableau, ils ont donc décidé de faire des économies, ce qui s'est avéré être une mauvaise décision à long terme.

32voto

Kerrek SB Points 194696

Voici une autre perspective : Il n'y a pas un seul type "tableau" en C. Au contraire, T[N] est un a a différents pour chaque N . Donc T[1] , T[2] etc., sont tous différents types .

En C, il n'y a pas de surcharge de fonctions, et donc la seule chose sensée que vous auriez pu autoriser serait une fonction qui prend (ou renvoie) une fonction un seul type de tableau :

void foo(int a[3]);  // hypothetical

Vraisemblablement, cela a été considéré comme beaucoup moins utile que la décision actuelle de faire en sorte que tous les tableaux se décomposent en un pointeur sur le premier élément et que l'utilisateur doive communiquer la taille par d'autres moyens. Après tout, ce qui précède pourrait être réécrit comme suit :

void foo(int * a)
{
  static const unsigned int N = 3;
  /* ... */
}

Il n'y a donc pas de perte de puissance expressive, mais un gain énorme en généralité.

Notez que cela n'est pas différent en C++, mais la génération de code basée sur des modèles vous permet d'écrire une fonction modélisée foo(T (&a)[N]) , donde N est déduit pour vous - mais cela signifie simplement que vous pouvez créer une famille entière de distinct, différent fonctions, une pour chaque valeur de N .

Dans un cas extrême, imaginez que vous ayez besoin de deux fonctions <code>print6(const char[6])</code> y <code>print12(const char[12])</code> pour dire <code>print6("Hello")</code> y <code>print12("Hello World")</code> si vous ne voulez pas décomposer les tableaux en pointeurs, sinon vous devrez ajouter une conversion explicite, <code>print_p((const char*)"Hello World")</code> .

0 votes

Il est intéressant de noter que certaines autres langues faire permettent de passer des tableaux en tant que paramètres. En Ada, par exemple, l'équivalent de int[5] y int[10] son (ou du moins peuvent l'être) le même type ; ce sont juste des sous-types différents. Vous pouvez définir une routine Ada qui prend en paramètre un tableau d'entiers avec des limites arbitraires, ou (pour une fonction) qui retourne un tel tableau. Le prix à payer pour cela est que le compilateur doit générer du code pour faire toute la comptabilité et la gestion de la mémoire nécessaires. Un tel code implicite n'est généralement pas considéré comme étant "dans l'esprit du C" (ou du C++).

8voto

David Schwartz Points 70129

La raison pour laquelle vous ne pouvez pas passer un tableau par valeur est qu'il n'existe pas de moyen spécifique de suivre la taille d'un tableau de telle sorte que la logique d'invocation de la fonction sache combien de mémoire allouer et ce qu'il faut copier. Vous pouvez passer une instance de classe parce que les classes ont des constructeurs. Les tableaux n'en ont pas.

2 votes

Si le tableau est déclaré comme a[4], il suffit de connaître sa taille au moment de la compilation.

1 votes

Oui, si . Mais la taille n'est pas transmise avec le tableau, ils ne sont pas "collés" ensemble de la manière qui serait nécessaire pour permettre aux tableaux d'être transmis par valeur.

0 votes

@quant : dans la portée initiale, on le sait, mais où va le 4 dans la fonction appelée ?

0voto

KonradG Points 11

Vous son passer par valeur : la valeur du pointeur vers le tableau. Rappelez-vous que l'utilisation de la notation entre crochets en C est simplement un raccourci pour déréférencer un pointeur. ptr[2] signifie *(ptr+2).

En supprimant les parenthèses, vous obtenez un pointeur sur le tableau, qui peut être transmis par valeur à une fonction :

int x[2] = {1, 2};
int result;
result = DoSomething(x);

Voir le liste des types dans la spécification C de l'ANSI. Les tableaux ne sont pas des types primitifs, mais construits à partir d'une combinaison de pointeurs et d'opérateurs. (Je ne peux pas mettre un autre lien, mais la construction est décrite sous "Array type derivation").

0 votes

Vous ne passez pas l'adresse du tableau, vous passez l'adresse du premier élément du tableau (même emplacement mémoire, type différent). L'opération d'indexation d'un tableau est par définition une combinaison de l'arithmétique des pointeurs et de la fonction unaire * mais un tableau lui-même n'est qu'un tableau. Ce qui fait que les tableaux ne sont pas des types de première classe en C n'est pas les objets tableaux eux-mêmes, mais l'ensemble limité d'opérations sur eux.

0 votes

Vous parlez des tableaux en tant que concept de programmation : les structures de données du point de vue du programmeur. Je pensais que la question était de savoir pourquoi la syntaxe C pour les données de tableaux semble différer des autres données. Si l'on considère cela comme une question de structure de langage, c'est parce que les tableaux ne sont pas des primitives. Ce sont des opérations de pointeurs qui se comportent presque comme des primitives.

0 votes

Le plus opérations sur les tableaux sont implémentées comme des opérations sur les pointeurs. Tableaux ne sont pas les pointeurs. Par exemple, un objet tableau est un objet tableau, et définir un objet tableau ne crée pas explicitement ou implicitement un objet pointeur. (Et je ne suis pas du tout sûr de comprendre la distinction que vous faites entre "structures de données" et "structure de langage").

0voto

Andre Holzner Points 6419

L'équivalent de cela serait de faire d'abord une copie du tableau et de le passer ensuite à la fonction (ce qui peut être très inefficace pour les grands tableaux).

Sinon, je dirais que c'est pour des raisons historiques, c'est-à-dire qu'on ne pouvait pas passer des tableaux par valeur en C.

Je pense que la raison pour laquelle on n'a PAS introduit le passage des tableaux par valeur en C++ était que l'on pensait que les objets avaient une taille modérée par rapport aux tableaux.

Comme l'a souligné delnan, lorsque l'on utilise std::vector vous pouvez en fait passer des objets de type tableau aux fonctions par valeur.

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