Dans tous nos cours C ++, tous les professeurs mettent toujours using namespace std;
juste après le #include
s dans leurs .h
fichiers. Cela me semble dangereux car en incluant cet en-tête dans un autre programme j'obtiendrai l'espace de noms importé dans mon programme, peut-être sans le réaliser, le vouloir ou le vouloir (l'inclusion d'en-tête peut être très profondément imbriquée).
Ma question est donc double: ai-je raison de using namespace
ne pas utiliser dans les fichiers d'en-tête, et / ou y a-t-il un moyen de l'annuler, quelque chose comme:
//header.h
using namespace std {
.
.
.
}
Une autre question dans le même sens: un fichier d'en-tête devrait-il contenir #include
tous les en-têtes dont son .cpp
fichier correspondant a besoin, uniquement ceux qui sont nécessaires pour les définitions d'en-tête et laisser le .cpp
fichier #include
le reste, ou aucun et déclarer tout ce dont il a besoin extern
?
Le raisonnement derrière la question est le même que ci-dessus: je ne veux pas de surprises lors de l'inclusion de .h
fichiers.
De plus, si j'ai raison, est-ce une erreur courante? Je veux dire dans la programmation du monde réel et dans les «vrais» projets là-bas.
Je vous remercie.
la source
using namespace
instructions, vous pouvez utiliser le nom complet pour résoudre le problème.Réponses:
Vous ne devriez certainement PAS utiliser
using namespace
dans les en-têtes précisément pour la raison que vous dites, que cela peut changer de manière inattendue la signification du code dans tous les autres fichiers qui incluent cet en-tête. Il n'y a aucun moyen d'annuler unusing namespace
qui est une autre raison pour laquelle c'est si dangereux. J'utilise généralement justegrep
ou similaire pour m'assurer que celausing namespace
n'est pas appelé dans les en-têtes plutôt que d'essayer quelque chose de plus compliqué. Les vérificateurs de code statiques le signalent probablement aussi.L'en-tête doit inclure uniquement les en-têtes dont il a besoin pour compiler. Un moyen simple de faire respecter cela est de toujours inclure le propre en-tête de chaque fichier source en premier lieu, avant les autres en-têtes. Ensuite, la compilation du fichier source échouera si l'en-tête n'est pas autonome. Dans certains cas, par exemple en faisant référence à des classes de détail d'implémentation dans une bibliothèque, vous pouvez utiliser des déclarations avant au lieu de
#include
parce que vous avez un contrôle total sur la définition de cette classe déclarée avant.Je ne suis pas sûr que je l'appellerais commun, mais cela apparaît définitivement de temps en temps, généralement écrit par de nouveaux programmeurs qui ne sont pas conscients des conséquences négatives. En règle générale, un peu d'éducation sur les risques permet de résoudre tous les problèmes, car ils sont relativement simples à résoudre.
la source
using
déclarations dans nos.cpp
fichiers? les3rdPartyLib::BigClassName<3rdPartyLib::AnotherBigName,3rdPartyLib::AnotherBigName>::Iterator
s sont la mort au bout des doigts.template
fonctions - qui sont censées être dans les en-têtes?typedefs
?using
instructions dans des.cpp
fichiers sans trop de soucis car la portée sera limitée à ce fichier, mais ne le faites jamais avant une#include
instruction. En ce qui concerne les fonctions de modèle définies dans les en-têtes, malheureusement, je ne connais pas de bonne solution autre que la simple écriture de l'espace de noms ... Vous pourriez peut-être mettre unusing
déclaration dans une portée séparée{ /* using statement in between brackets */ }
, cela l'empêcherait au moins de s'échapper du fichier actuel .Point 59 dans Sutter et Alexandrescu «Normes de codage C ++: 101 règles, directives et meilleures pratiques» :
Un fichier d'en-tête est un invité dans un ou plusieurs fichiers source. Un fichier d'en-tête qui comprend des
using
directives et des déclarations apporte aussi ses copains tapageurs.Une
using
déclaration amène un copain. Uneusing
directive fait entrer tous les copains dans l'espace de noms. L'utilisation par vos professeurs deusing namespace std;
est une directive d'utilisation.Plus sérieusement, nous avons des espaces de noms pour éviter les conflits de noms. Un fichier d'en-tête est destiné à fournir une interface. La plupart des en-têtes ne savent pas quel code peut les inclure, maintenant ou dans le futur. L'ajout d'
using
instructions pour des raisons de commodité interne dans l'en-tête applique ces noms pratiques à tous les clients potentiels de cet en-tête. Cela peut conduire à des conflits de noms. Et c'est tout simplement impoli.la source
Vous devez être prudent lorsque vous ajoutez des en-têtes à l'intérieur des en-têtes. Dans les grands projets, il peut créer une chaîne de dépendances très enchevêtrée qui déclenche des reconstructions plus importantes / plus longues que ce qui était réellement nécessaire. Consultez cet article et son suivi pour en savoir plus sur l'importance d'une bonne structure physique dans les projets C ++.
Vous ne devez inclure les en-têtes dans un en-tête que lorsque cela est absolument nécessaire (chaque fois que la définition complète d'une classe est nécessaire), et utiliser la déclaration directe partout où vous le pouvez (lorsque la classe est requise est un pointeur ou une référence).
En ce qui concerne les espaces de noms, j'ai tendance à utiliser la portée de l'espace de noms explicite dans mes fichiers d'en-tête et à ne mettre un
using namespace
dans mes fichiers cpp.la source
template
déclaration de fonction? cela doit se produire dans l'en-tête, non?Consultez les normes de codage du Goddard Space Flight Center (pour C et C ++). Cela s'avère être un peu plus difficile qu'auparavant - voir les réponses mises à jour aux questions SO:
La norme de codage GSFC C ++ dit:
La première des questions croisées comprend maintenant une citation de la norme de codage GSFC C et la justification, mais la substance finit par être la même.
la source
Vous avez raison de dire que l'
using namespace
en-tête est dangereux. Je ne sais pas comment le défaire. Il est facile de le détecter mais il suffit de rechercherusing namespace
dans les fichiers en-tête. Pour cette dernière raison, il est rare dans les projets réels. Des collègues plus expérimentés se plaindront bientôt si quelqu'un fait quelque chose comme ça.Dans de vrais projets, les gens essaient de minimiser la quantité de fichiers inclus, car moins vous en incluez, plus la compilation est rapide. Cela fait gagner du temps à tout le monde. Cependant, si le fichier d'en-tête suppose que quelque chose doit être inclus avant lui, il doit l'inclure lui-même. Sinon, cela rend les en-têtes non autonomes.
la source
Vous avez raison. Et tout fichier ne doit inclure que les en-têtes nécessaires à ce fichier. Quant à "faire les choses mal est-il courant dans les projets du monde réel?" - Oh oui!
la source
Comme toute chose en programmation, le pragmatisme devrait l'emporter sur le dogmatisme, l'OMI.
Tant que vous prenez la décision à l'échelle du projet ("Notre projet utilise largement STL, et nous ne voulons pas avoir à tout ajouter avec std ::."), Je ne vois pas le problème avec cela. La seule chose que vous risquez, ce sont les collisions de noms, après tout, et avec l'omniprésence de la STL, il est peu probable que ce soit un problème.
D'un autre côté, s'il s'agissait d'une décision d'un développeur dans un seul fichier d'en-tête (non privé), je peux voir comment cela générerait de la confusion au sein de l'équipe et devrait être évité.
la source
En ce qui concerne "Y a-t-il un moyen d'annuler [a
using
déclaration]?"Je pense qu'il est utile de souligner que les
using
déclarations sont affectées par la portée.Donc effectivement oui. En limitant la portée de la
using
déclaration, son effet ne dure que dans cette portée; il est «annulé» lorsque cette portée se termine.Lorsque la
using
déclaration est déclarée dans un fichier en dehors de toute autre portée, elle a une portée de fichier et affecte tout ce qui se trouve dans ce fichier.Dans le cas d'un fichier d'en-tête, si la
using
déclaration est à portée de fichier, cela s'étendra à la portée de tout fichier dans lequel l'en-tête est inclus.la source
namespace
déclaration) par rapport à la façon dont elle fonctionne réellement (comme une variable).{}
l'enfermant limiter sa portée,{}
après qu'il ne fasse rien à ce sujet. C'est une manière accidentelle que leusing namespace
est appliqué globalement.Je pense que vous pouvez utiliser `` using '' dans les en-têtes C ++ en toute sécurité si vous écrivez vos déclarations dans un espace de noms imbriqué comme celui-ci:
Cela ne doit inclure que les éléments déclarés dans 'DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED' sans les espaces de noms utilisés. Je l'ai testé sur le compilateur mingw64.
la source
using
déclarations dans les définitions de fonction où je peux afin qu'elles ne polluent pas les espaces de noms en dehors de la fonction. Mais maintenant, je souhaite utiliser des littéraux définis par l'utilisateur C ++ 11 dans un fichier d'en-tête, et selon la convention habituelle, les opérateurs littéraux sont protégés par un espace de noms; mais je ne veux pas les utiliser dans des listes d'initialiseurs de constructeurs qui ne sont pas dans une portée où je peux utiliser uneusing
déclaration non polluante . C'est donc idéal pour résoudre ce problème.error: ... DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED:: DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED::ClassName ...
. Au moins, c'est ce qui se passe pour moi dans g ++.