"utiliser namespace" dans les en-têtes c++
dans tous nos cours de c++, Tous les enseignants mettent toujours using namespace std;
juste après #include
dans leurs fichiers .h
. Cela me semble dangereux depuis lors en incluant cet en-tête dans un autre programme je vais faire importer l'Espace-nom dans mon programme, peut-être sans m'en rendre compte, avec l'intention ou en voulant (l'inclusion de l'en-tête peut être très profondément imbriquée).
donc ma question Est double: ai-je raison que using namespace
ne devrait pas être utilisé dans les fichiers d'en-tête, et/ou est-il possible de l'annuler, quelque chose comme:
//header.h
using namespace std {
.
.
.
}
une question de plus dans le même ordre: un fichier d'en-tête #include
devrait-il avoir tous les en-têtes dont il a besoin, seulement 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 comme extern
?
Le raisonnement derrière la question Est le même que ci-dessus: je ne vous voulez des surprises en incluant les fichiers .h
.
aussi, si j'ai raison, est-ce une erreur courante? Je veux dire dans la programmation du monde réel et dans les projets "réels" là-bas.
Merci.
9 réponses
vous ne devriez certainement pas utiliser using namespace
dans les en-têtes pour précisément la raison que vous dites, qu'il peut changer de façon inattendue la signification du code dans d'autres fichiers qui incluent cet en-tête. Il n'y a aucun moyen de défaire un using namespace
ce qui est une autre raison pour laquelle il est si dangereux. En général, j'utilise simplement grep
ou un truc du genre pour m'assurer que using namespace
n'est pas appelé dans les en-têtes plutôt que d'essayer quelque chose de plus compliqué. Probablement les vérificateurs de code statique signalent cela aussi.
L'en-tête doit inclure juste les en-têtes qu'il doit compiler. Un moyen facile de faire respecter ceci est de toujours inclure l'en-tête propre à chaque fichier source comme première chose, avant tout autre en-tête. Alors le fichier source ne compilera pas si l'en-tête n'est pas autonome. Dans certains cas, par exemple en se référant à des classes implementation-detail dans une bibliothèque, vous pouvez utiliser des déclarations forward au lieu de #include
parce que vous avez le contrôle total sur la définition d'un tel forward déclaré classe.
Je ne suis pas sûr que je l'appellerais commun, mais il apparaît certainement une fois de temps en temps, généralement écrit par de nouveaux programmeurs qui ne sont pas conscients des conséquences négatives. Typiquement, juste un peu d'éducation sur les risques prend soin de tous les problèmes car il est relativement simple à réparer.
Article 59 de Sutter et Alexandrescu "C++ Normes de Codage: 101 Règles, des lignes Directrices et des Pratiques Exemplaires":
- N'écrivez pas les utilisations de namespace dans un fichier d'en-tête ou avant un #include. 108
les titres de toutes les lignes directrices sont à http://www.gotw.ca/publications/c++cs.htm , mais les détails sont incontournables pour les développeurs C++.
vous devez être prudent lorsque vous incluez des en-têtes à l'intérieur des en-têtes. Dans les grands projets, elle peut créer une chaîne de dépendances très enchevêtrée qui déclenche des reconstructions plus grandes/plus longues que celles qui étaient réellement nécessaires. Voir 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 à l'intérieur d'un en-tête que lorsque cela est absolument nécessaire ( la définition complète d'une classe est nécessaire), et utilisez la déclaration forward 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 explicite de l'espace de noms dans Mes fichiers d'en-tête, et j'ai seulement mis un using namespace
dans mes fichiers cpp.
consultez les normes de codage du Goddard Space Flight Center (pour C et C++). Cela s'avère un peu plus difficile qu'avant - voir les réponses mises à jour aux questions SO:
la norme de codage C++ du GSFC dit:
§3.3.7 chaque fichier d'en-tête doit
#include
les fichiers qu'il doit compiler, plutôt que de forcer les utilisateurs à#include
les fichiers nécessaires.#includes
doit être limité à ce dont l'en-tête a besoin; l'autre#includes
doit être placé dans le fichier source.
la première des questions de renvoi comprend maintenant une citation de la norme de codage C du CFSG et la justification, mais la substance finit par être la même.
vous avez raison, using namespace
dans header est dangereux.
Je ne sais pas un moyen de l'annuler.
Il est facile de le détecter mais il suffit de rechercher using namespace
dans les fichiers d'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 les projets réels les gens essaient de minimiser la quantité de fichiers inclus, parce que moins vous incluez le plus rapide il compile. Un gain de temps de tout le monde. Toutefois, si le fichier d'en-tête suppose que quelque chose doit être inclus avant, puis il devrait comprendre elle-même. Sinon, les en-têtes ne sont pas autonomes.
vous avez raison. Et tout fichier ne doit inclure que les en-têtes nécessaires à ce fichier. Comme pour "faire les choses mal commun dans le monde réel des projets?"- oh, oui!
comme toute chose dans la programmation, le pragmatisme devrait l'emporter sur le dogmatisme, IMO.
tant que vous prenez la décision à l'échelle du projet ("Notre projet utilise largement STL, et nous ne voulons pas avoir à tout préparer avec std:."), Je ne vois pas le problème avec lui. La seule chose que vous risquez, ce sont les collisions de noms, Après tout, et avec L'ubiquité de STL, il est peu probable que ce soit un problème.
d'autre part, s'il s'agit d'une décision d'un développeur dans un seul en-tête (non privé) - fichier, je peux voir comment il générerait la confusion parmi l'équipe et devrait être évitée.
je crois 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 ceci:
namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED
{
/*using statements*/
namespace DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED
{
/*declarations*/
}
}
using namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED::DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED;
cela ne devrait inclure que les choses déclarées dans "DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUSES" sans les espaces de noms utilisés. Je l'ai testé sur mingw64 compilateur.
quant à "Est-il un moyen pour annuler [ using
déclaration]?"
je pense qu'il est utile de souligner que les déclarations using
sont affectées par le champ d'application.
#include <vector>
{ // begin a new scope with {
using namespace std;
vector myVector; // std::vector is used
} // end the scope with }
vector myOtherVector; // error vector undefined
std::vector mySTDVector // no error std::vector is fully qualified
donc effectivement Oui. En limitant le champ d'application de la déclaration using
, son effet ne dure qu'à l'intérieur de ce champ d'application; il est "Annulé" lorsque ce champ d'application prend fin.
lorsque la déclaration using
est déclarée dans un dossier en dehors de toute autre portée, il a fichier-champ d'application et affecte tout dans ce fichier.
dans le cas d'un fichier d'en-tête, si la déclaration using
se trouve à file-scope ceci s'étendra à la portée de tout fichier dans lequel l'en-tête est inclus.