135 votes

"En utilisant l'espace de noms" dans les en-têtes de C++

Dans tous nos cours de c++, tous les enseignants mettent toujours using namespace std; juste après les #include dans leurs fichiers .h. Cela me semble être dangereux car en incluant ensuite cet en-tête dans un autre programme, je vais importer l'espace de noms dans mon programme, peut-être sans m'en rendre compte, sans l'intention ou sans le vouloir (l'inclusion d'en-têtes peut être très profondément imbriquée).

Alors ma question est double : Ai-je raison de penser que using namespace ne devrait pas être utilisé 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 #include tous les en-têtes dont le fichier .cpp correspondant a besoin, seulement ceux nécessaires pour les définitions de l'en-tête et laisser le fichier .cpp #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 veux pas de surprises en incluant des 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" qui existent.

Merci.

3 votes

En tant que note complémentaire, si vous rencontrez des collisions de noms en raison des déclarations using namespace, vous pouvez utiliser le nom entièrement qualifié pour résoudre le problème.

131voto

Mark B Points 60200

Vous ne devriez certainement PAS utiliser using namespace dans les en-têtes pour la raison précise que vous mentionnez, à savoir que cela peut changer de manière inattendue le sens du code dans tout autre fichier qui inclut cet en-tête. Il n'y a aucun moyen d'annuler un using namespace, ce qui en fait une pratique très dangereuse. En général, j'utilise simplement grep ou similaire 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 que les vérificateurs de code statique signalent également cela.

L'en-tête ne devrait inclure que les en-têtes dont il a besoin pour être compilé. Un moyen simple de le garantir est d'inclure toujours le propre en-tête de chaque fichier source en premier, avant tout autre en-tête. Ainsi, le fichier source échouera à la compilation si l'en-tête n'est pas auto-suffisant. Dans certains cas, par exemple en faisant référence à des classes détaillées de l'implémentation dans une bibliothèque, vous pouvez utiliser des déclarations anticipées au lieu de #include car vous avez un contrôle total sur la définition d'une classe ainsi déclarée de manière anticipée.

Je ne suis pas sûr que je qualifierais cela de courant, mais cela arrive certainement de temps en temps, généralement écrit par de nouveaux programmeurs qui ne sont pas conscients des conséquences négatives. Généralement, un peu d'éducation sur les risques suffit à résoudre tout problème, car il est relativement simple à corriger.

2 votes

Sommes-nous libres d'utiliser des déclarations using dans nos fichiers .cpp? les 3rdPartyLib::BigClassName<3rdPartyLib::AnotherBigName,3rdPartyLib::AnotherBigName>::Iterators sont mortels pour les bouts des doigts.

1 votes

Et comment devrions-nous rationaliser les fonctions de template -- qui sont censées être dans les en-têtes ? typedefs?

1 votes

@donlan, il semble que vous n'ayez pas eu de réponse depuis un certain temps... Oui, vous pouvez utiliser des balises using dans les fichiers .cpp sans trop de soucis car la portée sera limitée à ce fichier uniquement, mais ne le faites jamais avant une balise #include. 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 d'écrire le nom de l'espace de noms... Peut-être pourriez-vous mettre une déclaration using dans une portée séparée { /* utilisation de la balise entre les crochets */ }, cela empêcherait au moins qu'elle ne s'échappe du fichier actuel.

36voto

Andy Thomas Points 30979

Article 59 dans les "Normes de codage C++ : 101 règles, directives et bonnes pratiques" de Sutter et Alexandrescu:

59. Ne pas écrire de déclarations de namespace using dans un fichier d'en-tête ou avant un #include.

Les using de namespace sont pour votre convenance, pas pour infliger aux autres : Ne jamais écrire une déclaration using ou une directive using avant une directive #include.

Corollaire : Dans les fichiers d'en-tête, ne pas écrire de directives de using au niveau du namespace ou de déclarations using; au lieu de cela, qualifier explicitement tous les noms avec le namespace.

Un fichier d'en-tête est un invité dans un ou plusieurs fichiers source. Un fichier d'en-tête qui inclut des directives et déclarations using amène aussi ses camarades bruyants.

Une déclaration using amène un camarade. Une directive using amène tous les camarades dans le namespace. L'utilisation de using namespace std; par vos professeurs est une directive using.

Plus sérieusement, nous avons des namespaces pour éviter les conflits de noms. Un fichier d'en-tête est censé fournir une interface. La plupart des en-têtes sont agnostiques quant au code qui pourrait les inclure, maintenant ou dans le futur. Ajouter des déclarations using pour des besoins internes à l'intérieur de l'en-tête impose ces noms pratiques à tous les clients potentiels de cet en-tête. Cela peut entraîner des conflits de noms. Et c'est simplement impoli.

13voto

Mike O'Connor Points 2650

Il faut être prudent lorsque vous incluez des en-têtes à l'intérieur d'autres en-têtes. Dans de grands projets, cela peut créer une chaîne de dépendances très complexe qui déclenche des reconstructions plus importantes/plus longues que 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 devriez inclure des en-têtes à l'intérieur d'un en-tête que lorsque c'est absolument nécessaire (toutes les fois où la définition complète d'une classe est requise), et utiliser des déclarations avancées chaque fois que possible (lorsque la classe requise est un pointeur ou une référence).

En ce qui concerne les espaces de noms, j'ai tendance à utiliser un espacement de namespace explicite dans mes fichiers d'en-tête, et à n'inclure qu'un using namespace dans mes fichiers cpp.

1 votes

Comment simplifiez-vous la déclaration de la fonction template ? Cela doit se produire dans l'en-tête, n'est-ce pas ?

7voto

Jonathan Leffler Points 299946

Découvrez les normes de codage du Goddard Space Flight Center (pour C et C ++). Cela s'avère un peu plus difficile qu'auparavant - consultez 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 dont il a besoin pour être compilé, plutôt que de forcer les utilisateurs à #include les fichiers nécessaires. Les #includes doivent être limités à ce dont l'en-tête a besoin ; les autres #includes doivent être placés dans le fichier source.

La première des questions en référence croisée inclut maintenant une citation de la norme de codage C du GSFC, et la raison, mais le contenu finit par être le même.

5voto

Öö Tiib Points 4755

Vous avez raison que using namespace dans l'en-tête est dangereux. Je ne sais pas comment l'annuler. Il est facile de le détecter cependant il suffit de chercher using namespace dans les fichiers d'en-tête. Pour cette dernière raison, c'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 le nombre de fichiers inclus, car moins vous incluez, plus rapidement cela compile. Cela économise du temps à tout le monde. Cependant, si le fichier d'en-tête suppose que quelque chose doit être inclus avant, alors il devrait l'inclure lui-même. Sinon, cela rend les en-têtes non autosuffisants.

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