Je vois souvent dans les codes C et C ++ la convention suivante:
some_type val;
val = something;
some_type *ptr = NULL;
ptr = &something_else;
au lieu de
some_type val = something;
some_type *ptr = &something_else;
Au départ, j’imaginais que c’était une habitude de l’époque où il fallait déclarer toutes les variables locales en haut de la portée. Mais j’ai appris à ne pas écarter si vite les habitudes des développeurs chevronnés. Alors, y a-t-il une bonne raison de déclarer sur une ligne et d’attribuer ensuite?
Réponses:
C
Dans C89, toutes les déclarations devaient se trouver au début d'un scope (
{ ... }
), mais cette exigence a été rapidement supprimée (d'abord avec les extensions du compilateur et ensuite avec le standard).C ++
Ces exemples ne sont pas les mêmes.
some_type val = something;
appelle le constructeur de copie, tandis queval = something;
le constructeur par défaut, puis laoperator=
fonction. Cette différence est souvent critique.Habitudes
Certaines personnes préfèrent d'abord déclarer les variables et les définir plus tard, dans le cas où elles reformateraient leur code ultérieurement avec les déclarations à un endroit et la définition à un autre.
Concernant les pointeurs, certaines personnes ont juste l'habitude d'initialiser chaque pointeur
NULL
ounullptr
quoi qu'il fasse avec ce pointeur.la source
some_type
constructeur prenantsomething
comme unique argument. C'est un cas très intéressant et inhabituel en C ++ ... cela signifie qu'il y a une présomption sur la signification sémantique de ces opérations.Vous avez balisé vos questions C et C ++ en même temps, alors que la réponse est très différente dans ces langages.
Premièrement, le libellé du titre de votre question est incorrect (ou, plus précisément, sans pertinence pour la question elle-même). Dans vos deux exemples, la variable est déclarée et définie simultanément, sur une ligne. La différence entre vos exemples réside dans le fait que dans le premier cas, les variables sont laissées non initialisées ou initialisées avec une valeur fictive, puis une valeur significative lui est attribuée ultérieurement. Dans le deuxième exemple, les variables sont immédiatement initialisées .
Deuxièmement, en langage C ++, comme @nightcracker l'a noté dans sa réponse, ces deux constructions sont sémantiquement différentes. Le premier repose sur l'initialisation tandis que le second - sur l'affectation. En C ++, ces opérations sont surchargeables et peuvent donc potentiellement conduire à des résultats différents (bien que l'on puisse noter que produire des surcharges non équivalentes d'initialisation et d'affectation n'est pas une bonne idée).
Dans le langage C standard d'origine (C89 / 90), il est illégal de déclarer des variables au milieu du bloc. C'est pourquoi vous pouvez voir des variables déclarées non initialisées (ou initialisées avec des valeurs nominales) au début du bloc, puis affectées de manière significative. les valeurs plus tard, lorsque ces valeurs significatives deviennent disponibles.
En langage C99, il est correct de déclarer des variables au milieu du bloc (comme en C ++), ce qui signifie que la première approche n'est nécessaire que dans certaines situations spécifiques lorsque l'initialiseur n'est pas connu au moment de la déclaration. (Cela s'applique aussi au C ++).
la source
some_type val;
immédiatement la variable . C'est ce que je voulais dire dans ma réponse.val
Je pense que c'est une vieille habitude, issue de la "déclaration locale". Et donc comme réponse à votre question: Non, je ne pense pas qu'il y ait une bonne raison. Je ne le fais jamais moi-même.
la source
J'ai dit quelque chose à ce sujet dans ma réponse à une question d'Helium3 .
En gros, je dis que c'est un moyen visuel de voir facilement ce qui change.
et
la source
Les autres réponses sont plutôt bonnes. Il y a une certaine histoire autour de cela en C. En C ++, il y a la différence entre un constructeur et un opérateur d'affectation.
Je suis surpris que personne ne mentionne le point supplémentaire: séparer les déclarations de l'utilisation d'une variable peut parfois être beaucoup plus lisible.
Visuellement, lors de la lecture du code, les artefacts les plus banals, tels que les types et les noms de variables, ne vous interpellent pas. Ce sont les déclarations qui vous intéressent le plus, vous passez le plus de temps à regarder, et vous avez donc tendance à jeter un coup d'œil sur le reste.
Si certains types, noms et assignations se déroulent dans le même espace restreint, il y a un peu de surcharge d'informations. De plus, cela signifie que quelque chose d'important se passe dans l'espace sur lequel je regarde habituellement.
Cela peut sembler un peu contre-intuitif, mais c’est un exemple où il peut être meilleur de prendre de la place pour votre source. Je vois cela comme une raison pour laquelle vous ne devriez pas écrire de lignes encombrées qui font des quantités folles d’arithmétique de pointeur et d’assignation dans un espace vertical restreint - ce n’est pas parce que le langage vous laisse échapper de telles choses que vous ne devriez pas le faire. tout le temps. :-)
la source
En C, c'était la pratique habituelle, car les variables devaient être déclarées au début de la fonction, contrairement à C ++, où elles pouvaient être déclarées n'importe où dans le corps de la fonction pour être utilisées par la suite. Les pointeurs étaient réglés sur 0 ou sur NULL, car ils s'assuraient simplement que le pointeur ne pointait pas. Autrement, je ne peux penser à aucun avantage important qui oblige quiconque à faire de même.
la source
Avantages pour la localisation des définitions de variables et leur initialisation significative:
si une valeur significative est habituellement attribuée aux variables lorsqu’elles apparaissent pour la première fois dans le code (une autre perspective de la même chose: vous retardez leur apparition jusqu’à ce qu’une valeur significative soit disponible), il n’ya aucune chance qu’elles soient accidentellement utilisées avec une valeur non significative ou non initialisée ( ce qui peut facilement arriver si une initialisation est accidentellement contournée à cause d’énoncés conditionnels, d’une évaluation de court-circuit, d’exceptions, etc.)
peut être plus efficace
operator=
peut parfois être moins efficace et nécessiter un objet temporaireminimiser à son tour la portée des variables minimise le nombre moyen de variables simultanément dans la portée : ceci
parfois plus concis que vous ne répétez pas le nom de la variable dans une définition puis dans une affectation significative initiale
nécessaire pour certains types tels que les références et lorsque vous souhaitez que l'objet soit
const
Arguments pour regrouper les définitions de variables:
il est parfois pratique et / ou concis de définir le type de plusieurs variables:
the_same_type v1, v2, v3;
(si la raison est simplement que le nom du type est trop long ou complexe, un
typedef
peut parfois être meilleur)Parfois, il est souhaitable de regrouper les variables indépendamment de leur utilisation pour mettre en valeur l'ensemble des variables (et des types) impliqués dans certaines opérations:
type v1;
type v2;
type v3;
Cela met l'accent sur les caractères communs des types et facilite un peu leur modification, tout en restant fidèle à une variable par ligne facilitant le copier-coller, les
//
commentaires, etc.Comme souvent dans la programmation, bien qu’une pratique puisse présenter des avantages empiriques évidents dans la plupart des situations, l’autre pratique peut être extrêmement améliorée dans quelques cas.
la source