2911 votes

Pourquoi "using namespace std ;" est-il considéré comme une mauvaise pratique ?

D'autres m'ont dit qu'écrire using namespace std; dans le code est erronée, et que je devrais utiliser std::cout y std::cin directement à la place.

Pourquoi est-ce que using namespace std; est-elle considérée comme une mauvaise pratique ? Est-elle inefficace ou risque-t-elle de déclarer des variables ambiguës (des variables qui partagent le même nom qu'une fonction en std espace de noms) ? Cela a-t-il un impact sur les performances ?

596 votes

N'oubliez pas que vous pouvez faire : "using std::cout ;" ce qui signifie que vous n'avez pas besoin de taper std::cout, mais que vous n'avez pas besoin d'utiliser tout l'espace de noms std en même temps.

77 votes

Il est particulièrement mauvais d'utiliser 'using namespace std' à la portée du fichier dans les fichiers d'en-tête. L'utiliser dans les fichiers sources (*.cpp) au niveau du fichier après toutes les inclusions n'est pas aussi mauvais, car son effet est limité à une seule unité de traduction. Son utilisation à l'intérieur de fonctions ou de classes est encore moins problématique, car son effet est limité à la portée de la fonction ou de la classe.

8 votes

Je déconseille l'utilisation de la directive using mais pour des espaces de noms spécifiques tels que std::literals::chrono_literals , Poco::Data:Keywords , Poco::Units et des trucs qui traitent des littéraux ou des astuces de lisibilité. Chaque fois que c'est dans les fichiers d'en-tête ou d'implémentation. Cela peut être acceptable dans la portée d'une fonction, je suppose, mais en dehors des littéraux et autres, ce n'est pas utile.

2474voto

Greg Hewgill Points 356191

Cela n'est pas du tout lié aux performances. Mais considérez ceci : vous utilisez deux bibliothèques appelées Foo et Bar :

using namespace foo;
using namespace bar;

Tout fonctionne bien, et vous pouvez appeler Blah() de Foo et Quux() de Bar sans problèmes. Mais un jour, vous passez à une nouvelle version de Foo 2.0, qui offre maintenant une fonction appelée Quux() . Maintenant, il y a un conflit : Foo 2.0 et Bar importent tous deux Quux() dans votre espace de nom global. Cela va demander un certain effort pour le corriger, surtout si les paramètres de la fonction correspondent.

Si vous aviez utilisé foo::Blah() y bar::Quux() puis l'introduction de foo::Quux() aurait été un non-événement.

499 votes

J'ai toujours aimé la fonction "import big_honkin_name as bhn" de Python, qui permet d'utiliser "bhn.quelque chose" plutôt que "big_honkin_name.quelque chose" - cela réduit vraiment la saisie. Est-ce que le C++ a quelque chose comme ça ?

840 votes

@Pax namespace io = boost::filesystem ;

164 votes

Je pense que c'est exagérer les choses que de dire que c'est "un certain effort à réparer". Vous n'aurez pas d'instances du nouveau foo::Quux, alors désambiguisez toutes vos utilisations actuelles avec bar::Quux.

1498voto

sbi Points 100828

Je suis d'accord avec tout. Greg a écrit mais j'aimerais ajouter : Ça peut même être pire que ce que Greg a dit !

La bibliothèque Foo 2.0 pourrait introduire une fonction, Quux() qui correspond mieux, sans ambiguïté, à certains de vos appels à Quux() que le bar::Quux() votre code a été appelé pendant des années. Puis votre le code compile toujours mais il appelle silencieusement la mauvaise fonction et fait Dieu sait quoi. C'est à peu près aussi mauvais que les choses peuvent devenir.

N'oubliez pas que le std possède des tonnes d'identifiants, dont beaucoup sont des muy communs (pensez list , sort , string , iterator ) qui sont très susceptibles d'apparaître dans d'autres codes également.

Si vous considérez que c'est peu probable : Il y avait une question posée ici, sur Stack Overflow, où il s'est passé à peu près exactement la même chose (mauvaise fonction appelée en raison d'une omission std:: préfixe) environ une demi-année après avoir donné cette réponse. Ici est un autre exemple, plus récent, d'une telle question. Il s'agit donc d'un véritable problème.


Voici un autre point de données : Il y a de très nombreuses années, je trouvais également ennuyeux de devoir préfixer tout ce qui provenait de la bibliothèque standard par le terme std:: . J'ai ensuite travaillé sur un projet où il avait été décidé dès le départ que les deux using Les directives et les déclarations sont interdites, sauf pour la portée des fonctions. Devinez quoi ? Il n'a fallu que quelques semaines à la plupart d'entre nous pour s'habituer à écrire le préfixe, et après quelques semaines supplémentaires, la plupart d'entre nous étaient même d'accord sur le fait que cela rendait le code plus lisible . Il y a une raison à cela : Que vous aimiez une prose plus courte ou plus longue est subjectif, mais les préfixes ajoutent objectivement de la clarté au code. Non seulement le compilateur, mais vous aussi, trouvez plus facile de voir à quel identifiant il est fait référence.

En une décennie, ce projet a atteint plusieurs millions de lignes de code. Comme ces discussions reviennent sans cesse, j'ai été un jour curieux de savoir combien de fois le champ d'application de la fonction (autorisé) using a été utilisé dans le projet. J'ai parcouru les sources pour le trouver et je n'ai trouvé qu'une ou deux douzaines d'endroits où il était utilisé. Pour moi, cela indique que, une fois essayé, les développeurs ne trouvent pas std:: assez douloureux pour employer des directives d'utilisation même une fois tous les 100 kLoC, même lorsque son utilisation était autorisée.


La ligne du bas : Préfixer tout explicitement ne fait pas de mal, demande très peu d'habitude et présente des avantages objectifs. En particulier, cela rend le code plus facile à interpréter par le compilateur et par les lecteurs humains - et cela devrait probablement être l'objectif principal quand on écrit du code.

481voto

ChrisW Points 37322

Le problème de mettre using namespace dans les fichiers d'en-tête de vos classes, c'est que cela oblige quiconque veut utiliser vos classes (en incluant vos fichiers d'en-tête) à "utiliser" (c'est-à-dire à voir tout ce qui se trouve dans) ces autres espaces de noms.

Cependant, vous pouvez vous sentir libre de mettre une déclaration using dans vos fichiers *.cpp (privés).


Attention, certaines personnes ne sont pas d'accord avec le fait que je dise "sentez-vous libre" comme ça, car bien qu'une using dans un fichier cpp est meilleur que dans un en-tête (parce que cela n'affecte pas les personnes qui incluent votre fichier d'en-tête), ils pensent que ce n'est pas encore bon (car selon le code, cela pourrait rendre l'implémentation de la classe plus difficile à maintenir). Cette entrée C++ Super-FAQ dit,

La directive using existe pour le code C++ hérité et pour faciliter la transition vers les espaces de noms, mais vous ne devriez probablement pas l'utiliser régulièrement, du moins pas dans votre nouveau code C++.

La FAQ suggère deux alternatives :

  • Une déclaration d'utilisation :

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
  • Il suffit de taper std: :

    std::cout << "Values:";

4 votes

Bien sûr, vous ne devriez jamais supposer l'état du cout global non plus, de peur que quelqu'un ait std:cout << std::hex et échoue à std::restore_cout_state par la suite. Mais c'est un tout autre fatberg.

0 votes

"Cependant, vous pouvez vous sentir libre de mettre une déclaration d'utilisation dans vos fichiers *.cpp (privés)". Et que se passera-t-il si une future équipe de développeurs décide de changer le schéma des unités de traduction, par exemple via UnityBuilds ? Dans le doute, vous vous retrouverez avec un horrible comportement indéfini.

0 votes

Si les préoccupations concernant les fichiers d'en-tête peuvent être justifiées, en raison de la façon dont les includes peuvent avoir des effets secondaires, je pense qu'elles ne le sont pas dans le cas des fichiers cpp. Regardons ce qui se passe dans pratiquement tous les autres langages de programmation. Par exemple, lorsque vous codez en Java, vous importez presque toujours chaque symbole des paquets que vous utilisez, en particulier les paquets standard. Cela signifie que vous ne vous attendez presque jamais à une implémentation concurrente et conflictuelle de String, List, Map, etc. Il en va de même pour les autres langages que je connais. C'est raisonnable et nous devrions rendre la vie facile et non difficile.

248voto

David Thornley Points 39051

Je suis récemment tombé sur une plainte concernant Visual Studio 2010 . Il s'est avéré que presque tous les fichiers sources contenaient ces deux lignes :

using namespace std;
using namespace boost;

Beaucoup de Boost sont intégrées à la norme C++0x, et Visual Studio 2010 comporte de nombreuses fonctionnalités C++0x, de sorte que, soudainement, ces programmes ne compilaient plus.

Par conséquent, il faut éviter using namespace X; est une forme d'anticipation, une façon de s'assurer qu'un changement dans les bibliothèques et/ou les fichiers d'en-tête utilisés ne va pas casser un programme.

20 votes

Ceci. Boost et std ont un lot de chevauchement - surtout depuis C++11.

1 votes

J'ai fait ça une fois et j'ai appris une leçon à la dure. Maintenant, je n'utilise jamais using en dehors de la définition d'une fonction et utilisent rarement using namespace du tout.

133voto

robson3.14 Points 1237

On ne devrait pas utiliser le using à l'échelle mondiale, en particulier dans les en-têtes. Cependant, il existe des situations où elle est appropriée même dans un fichier d'en-tête :

template <typename FloatType> inline
FloatType compute_something(FloatType x)
{
    using namespace std; // No problem since scope is limited
    return exp(x) * (sin(x) - cos(x * 2) + sin(x * 3) - cos(x * 4));
}

C'est mieux que la qualification explicite ( std::sin , std::cos ...), car il est plus court et a la capacité de travailler avec des types de virgule flottante définis par l'utilisateur (par l'intermédiaire de recherche en fonction de l'argument (ADL)).

4 votes

@Billy : Il n'y a pas d'autre moyen de supporter l'appel à userlib::cos(userlib::superint). Chaque fonctionnalité a son utilité.

17 votes

@Zan : Bien sûr qu'il y en a. using std::cos; , using std::sin etc. Le problème, c'est que tout système bien conçu userlib va avoir son sin y cos à l'intérieur de leur propre espace de nom également, ce qui ne vous aide pas vraiment. (A moins qu'il n'y ait un using namespace userlib avant ce modèle et c'est tout aussi mauvais que using namespace std -- et le champ d'application n'y est pas limité). En outre, la seule fonction de ce type à laquelle j'ai jamais vu cela arriver est la suivante swap Dans ce cas, je recommanderais de créer un modèle de spécialisation de l'option std::swap et éviter tout le problème.

1 votes

@Billy : Parfois, vous devrez surcharge (comme lorsque vous en avez besoin pour votre propre conteneur). Mais même dans ce cas, un local utilisant déclaration est bien meilleure qu'une directive using.

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