Question Pourquoi "utiliser namespace std" est-il considéré comme une mauvaise pratique?


J'ai été dit par d'autres que l'écriture using namespace std dans le code est faux, et que je devrais utiliser std::cout et std::cin directement à la place.

Pourquoi est-ce using namespace std considéré comme une mauvaise pratique? Est-il inefficace ou risque-t-il de déclarer des variables ambiguës (variables qui partagent le même nom qu'une fonction dans std espace de noms)? Cela affecte-t-il la performance?


2061
2017-09-21 03:08


origine


Réponses:


Ce n'est pas du tout lié à la performance. Mais considérez ceci: vous utilisez deux bibliothèques appelées Foo et Bar:

using namespace foo;
using namespace bar;

Tout fonctionne bien, 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(). Vous avez maintenant un conflit: Foo 2.0 et Bar import Quux() dans votre espace de noms global. Cela va prendre quelques efforts pour corriger, surtout si les paramètres de la fonction correspondent.

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


1746
2017-09-21 03:13



Je suis d'accord avec tout Greg a écrit, mais j'aimerais ajouter: Il peut même s'aggraver que Greg a dit!

Library Foo 2.0 pourrait introduire une fonction, Quux(), c'est une correspondance sans ambiguïté pour certains de vos appels à Quux() que le bar::Quux() votre code appelé pendant des années. Ensuite, votre le code compile toujours, mais il appelle silencieusement la mauvaise fonction et Dieu sait quoi. C'est à peu près aussi mauvais que les choses peuvent l'être.

Gardez à l'esprit que le std namespace a des tonnes d'identifiants, dont beaucoup sont très communs (pensez list, sort, string, iterator, etc.) qui sont très susceptibles d'apparaître dans d'autres codes, aussi.

Si vous considérez cela improbable: il y avait une question posée ici sur Stack Overflow où à peu près exactement cela est arrivé (mauvaise fonction appelée en raison d'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. Donc c'est un vrai problème.


Voici un autre point de données: Il y a de nombreuses années, j'avais l'habitude de trouver ennuyeux de devoir tout préfixer de la bibliothèque standard avec std::. Ensuite, j'ai travaillé dans un projet où il a été décidé au début que les deux using les directives et les déclarations sont interdites sauf pour les étendues de fonction. Devine quoi? Il nous a fallu très peu de temps à la plupart d'entre nous pour s'habituer à écrire le préfixe, et après quelques semaines, la plupart d'entre nous ont même convenu que le code avait effectivement été créé. plus lisible. Il y a une raison à cela: Si vous aimez la prose plus courte ou plus longue est subjective, mais les préfixes objectivement ajouter la clarté au code. Non seulement le compilateur, mais vous aussi, trouvez plus facilement quel identificateur est référencé.

En une décennie, ce projet a grandi pour avoir plusieurs millions de lignes de code. Puisque ces discussions reviennent encore et encore, j'ai été une fois curieux de savoir à quelle fréquence le champ d'application (autorisé) usingeffectivement été utilisé dans le projet. J'en ai trouvé les sources et n'ai trouvé qu'une ou deux douzaines d'endroits où elle était utilisée. Pour moi, cela indique que, une fois essayé, les développeurs ne trouvent pas std:: assez douloureux pour employer des directives même une fois toutes les 100 kLoC même là où il était autorisé à être utilisé.


Bottom line: Préfixer explicitement tout ne fait pas de mal, prend très peu de temps pour s'y habituer, et a 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 lors de l'écriture du code.


1147
2017-09-21 09:26



Je pense qu'il est mauvais de le mettre dans les fichiers d'en-tête de vos classes: parce que vous seriez obligé d'utiliser vos classes (en incluant vos fichiers d'en-tête) pour "utiliser" (c'est-à-dire tout voir) ces autres espaces de noms .

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


Méfiez-vous que certaines personnes ne sont pas d'accord avec ce que je dis «ne sentez pas libre» comme ceci - car même si une instruction using dans un fichier cpp est meilleur que dans un en-tête (car il n'affecte pas les personnes qui incluent votre fichier d'en-tête), ils pensent que ce n'est toujours pas bien (car en fonction du code, cela pourrait rendre l'implémentation de la classe plus difficile à maintenir). Ce sujet de 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 ++.

Il suggère deux alternatives:

  • Une déclaration utilisant:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
    
  • Passez-y et tapez simplement std ::

    std::cout << "Values:";
    

308
2017-09-21 03:22



J'ai récemment eu une plainte à propos de Visual Studio 2010. Il s'est avéré que presque tous les fichiers source avaient ces deux lignes:

using namespace std;
using namespace boost;

Beaucoup de Renforcer Les fonctionnalités vont dans le standard C ++ 0x, et Visual Studio 2010 a beaucoup de fonctionnalités C ++ 0x, donc soudainement ces programmes ne compilaient pas.

Par conséquent, en évitant using namespace X; est une forme d'anticipation, un moyen de s'assurer qu'une modification apportée aux bibliothèques et / ou fichiers d'en-tête utilisés ne va pas casser un programme.


197
2017-10-28 17:37



Version courte: n'utilisez pas de déclarations ou de directives globales dans les fichiers d'en-tête. N'hésitez pas à les utiliser dans les fichiers d'implémentation. Voici ce que disent Herb Sutter et Andrei Alexandrescu à propos de cette question Normes de codage C ++ (Bolding pour l'accent est le mien):

Résumé

Les utilisations de l'espace de nom sont pour votre commodité, et non pour vous infliger aux autres: N'écrivez jamais une déclaration using ou une directive using avant une directive #include.

Corollaire: Dans les fichiers d'en-tête, n'écrivez pas de niveau d'espace de noms à l'aide de directives ou de déclarations; à la place, explicitement espace de noms qualifier tous les noms. (La deuxième règle découle du premier, car les en-têtes ne peuvent jamais savoir quel autre en-tête #include pourrait apparaître après eux.)

Discussion

En bref: Vous pouvez et devez utiliser libéralement l'espace de noms en utilisant des déclarations et des directives dans vos fichiers d'implémentation après les directives #include et vous vous sentez bien à ce sujet. Malgré des affirmations répétées à l'effet contraire, l'espace de noms utilisant des déclarations et des directives n'est pas mauvais et ne va pas à l'encontre de l'objectif des espaces de noms. Au contraire, ils sont ce qui rend les espaces de noms utilisables.


159
2017-11-03 20:00



Il ne faut pas utiliser la directive à l'échelle globale, en particulier dans les en-têtes. Cependant, il existe des situations où il est approprié, 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 à virgule flottante définis par l'utilisateur (via Argument Dependent Lookup).


103
2017-09-21 15:47



Ne l'utilisez pas globalement

Il est considéré comme "mauvais" seulement quand utilisé globalement. Car:

  • Vous encombrez l'espace de noms dans lequel vous programmez.
  • Les lecteurs auront du mal à voir d'où provient un identifiant particulier, lorsque vous en utilisez beaucoup using namespace xyz.
  • Tout ce qui est vrai pour autre Les lecteurs de votre code source est encore plus vrai pour le lecteur le plus fréquent: vous-même. Revenez dans un an ou deux et jetez un coup d'oeil ...
  • Si vous parlez seulement de using namespace std vous pourriez ne pas être au courant de tout ce que vous attrapez - et quand vous ajoutez un autre #include ou passer à une nouvelle révision C ++ vous pourriez avoir des conflits de noms dont vous n'étiez pas au courant.

Vous pouvez l'utiliser localement

Allez-y et utilisez-le localement (presque) librement. Cela, bien sûr, vous empêche de la répétition de std:: - et la répétition est également mauvaise.

Un idiome pour l'utiliser localement

En C ++ 03 il y avait un idiome - code standard - pour mettre en œuvre un swap fonction pour vos classes. Il a été suggéré que vous utilisiez un local using namespace std -- ou au moins using std::swap:

class Thing {
    int    value_;
    Child  child_;
public:
    // ...
    friend void swap(Thing &a, Thing &b);
};
void swap(Thing &a, Thing &b) {
    using namespace std;      // make `std::swap` available
    // swap all members
    swap(a.value_, b.value_); // `std::stwap(int, int)`
    swap(a.child_, b.child_); // `swap(Child&,Child&)` or `std::swap(...)`
}

Cela fait la magie suivante:

  • Le compilateur choisira le std::swap pour value_, c'est à dire. void std::swap(int, int).
  • Si vous avez une surcharge void swap(Child&, Child&) implémenté le compilateur le choisira.
  • Si tu fais ne pas avoir cette surcharge le compilateur utilisera void std::swap(Child&,Child&) et essayez ses meilleurs échanges.

Avec C ++ 11, il n'y a plus de raison d'utiliser ce modèle. L'implémentation de std::swap a été changé pour trouver une surcharge potentielle et le choisir.


80
2018-01-18 09:34



Si vous importez les bons fichiers d'en-tête, vous avez soudain des noms comme hex, left, plus ou count dans votre portée mondiale. Cela pourrait être surprenant si vous n'êtes pas au courant std:: contient ces noms. Si vous essayez également d'utiliser ces noms localement, cela peut entraîner une certaine confusion.

Si tout le contenu standard est dans son propre espace de nom, vous n'avez pas à vous soucier des collisions de noms avec votre code ou d'autres bibliothèques.


71
2017-09-21 03:23