web-dev-qa-db-fra.com

Qu'est-ce que la pollution «utilisant l'espace de noms»?

Je regardais le guide de codage de Google [ici] et ils ne recommandent pas d'utiliser le using namespace ou namespace::function - si je ne l'ai pas mal interprété.

Est-ce que cela s'applique également à std? cout<< ne fonctionne pas sans lui. Ce livre , recommande la même chose. Alors, comment puis-je utiliser cout<< sans pour autant using namespace std; ou std::cout<<?

Quelle est la voie recommandée? std::cout<<? La plupart des manuels c ++ enseignent aux débutants avec using namespace std; propagent-ils de mauvaises pratiques de codage?

15
Lord Loh.

En lisant la norme Google, vous ne pouvez utiliser la directive using namespace foo; Nulle part. Cette directive apporte tout ce qui est déclaré dans l'espace de noms et est une cause courante de collisions et de comportements inattendus. D'autres en ont cité une très courante: vous avez votre propre méthode max ou min quelque part et elle entre en collision dans un fichier src où quelqu'un inclut un en-tête avec votre méthode et dit ensuite using namespace std;

Dans certains endroits, il est permis d'avoir une déclaration d'utilisation, qui est de la forme using ::foo::bar;

Les gens aiment mettre des directives d'utilisation dans leur code car cela économise beaucoup de frappe, mais cela comporte des risques. Si vous avez un fichier avec beaucoup d'instructions cout, je peux comprendre ne pas vouloir taper cent fois :: std :: cout, mais vous pouvez simplement dire en utilisant :: std :: cout. Je les traite comme des déclarations de variables: définissez-les là où elles sont nécessaires. Si une fonction dans un fichier de 10 a besoin d'écrire la sortie, ne déclarez pas le chemin cout en haut, mettez-la dans cette fonction qui fait la sortie réelle.

#include <ostream>
//using namespace std; // NO!
//using ::std::cout;   // less bad than using namespace, but I prefer to scope it

int main(int argc, char** argv)
{
   int rc = do_some_stuff(argc, argv);
   using ::std::endl;
   if (rc) { // print the success report
      using ::std::cout;
      cout << "The test run completed. The return code was " << rc << '.' << endl;
    } else {
      using ::std::cerr;
      cerr << "Unable to complete the test run." << endl;
    }
    return 0 == rc;
}

C'est un peu extrême avec seulement quelques lignes faisant la sortie, mais vous avez l'idée.

Une autre chose que l'on peut faire est un alias ou un typedef pour minimiser la frappe. Je ne trouve pas std :: que ce soit si mauvais, mais nous avons un énorme ensemble de sources avec plusieurs dizaines de modules et parfois nous devons écrire du code comme console_gui::command_window::append("text"). Cela devient fastidieux après un certain temps et cause beaucoup de longues files d'attente. Je suis tout pour quelque chose comme

typedef console_gui::command_window cw;
cw::append("text");

tant que les alias sont effectués dans une portée locale et conservent suffisamment de contexte pour rendre le code lisible.

18
Michael Mathews

C'est parce que: 1) il va à l'encontre de l'objectif des espaces de noms, qui est de réduire la collision de noms; 2) il met à la disposition de l'espace de noms global tout l'espace de noms spécifié avec la directive using.

Par exemple, si vous incluez et définissez votre propre fonction max (), elle entrera en collision avec std :: max ().

http://en.cppreference.com/w/cpp/algorithm/max

La préférence est d'utiliser std :: member_you_wish_to_use car il indique explicitement quel espace de noms utiliser.

8
ApplePie

Citant le lien que vous fournissez:

Vous pouvez utiliser une déclaration d'utilisation n'importe où dans un fichier .cc et dans des fonctions, des méthodes ou des classes dans des fichiers .h.

// OK dans les fichiers .cc.

// Doit être dans une fonction, une méthode ou une classe dans des fichiers .h.

en utilisant :: foo :: bar;

Le style Google vous interdit d'importer des espaces de noms dans un contexte global, mais permet de le faire dans des espaces locaux.

Partout où l'utilisation de la déclaration n'affecte qu'une partie limitée et clairement visible du code, elle est parfaitement acceptable.

Lorsque vous polluez le contexte global, le code non lié est affecté (implicitement en utilisant votre en-tête). Rien ne se produit lorsque vous le faites dans un contexte local.

6
Basilevs

Bien que la question ait déjà des réponses utiles, un détail semble trop court.

La plupart des programmeurs sont d'abord un peu confus avec le mot clé using et les descriptions de l'utilisation de namespace, même s'ils essaient de l'apprendre en recherchant la référence, car declaration and directive lit quelque peu équivalent, les deux sont des mots longs relativement abstraits commençant par d .

Les identificateurs dans les espaces de noms sont accessibles en nommant explicitement l'espace de noms:

myNamespace::myIdent

cela peut être beaucoup plus de touches à taper. Mais cela peut également diminuer la signification de votre code, si la plupart des identifiants sont préfixés de la même manière. Le mot clé using permet d'éviter ces inconvénients d'espace de noms. Puisque using fonctionne au niveau du compilateur (ce n'est pas une macro), son effet dure pour toute l'étendue dans laquelle il est utilisé. fichiers cpp.

... bien sûr, il y a une différence entre l'utilisation de la déclaration

using myNamespace::myIdent; // make myIdent an alias of myNamespace::myIdent

et en utilisant la directive

using myNamespace; // make all identifiers of myNamespace directly accessible

S'il est utilisé dans de vastes étendues, ce dernier conduit à beaucoup plus de confusion.

1
Wolf

ils ne recommandent pas que l'on utilise le namespace ornamespace: function` - si je ne l'ai pas mal interprété.

Tu l'as fait. La recommandation ne s'applique qu'aux using namespace directive (qui est communément appelée abusing namespace, pas entièrement avec humour). Il est fortement préférable d'utiliser le nom complet d'une fonction ou d'un objet, tel que std::cout.

1
H2CO3

Voici:

#include <iostream>

int main()
{
    std::endl(std::operator<<(std::cout, "Hello world!"));
}

En l'écrivant de cette façon, nous évitons l'ADL sujet aux erreurs ainsi que l'utilisation de directives et de déclarations.

Ceci est censé être une réponse sarcastique. :-RÉ

Je suis avec Herb Sutter sur Google sur celui-ci. Des normes de codage C++:

Vous pouvez et devrait utiliser l'espace de noms en utilisant les déclarations et les directives généreusement dans vos fichiers d'implémentation après les directives #include et vous en sentir bien. Malgré les affirmations répétées du 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. C'est plutôt ce qui rend les espaces de noms tilisables.

Vous pouvez être obsédé par les conflits d'espace de noms potentiels qui ne se manifesteront probablement jamais et ne seront probablement pas difficiles à résoudre dans un événement aussi astronomique rare en évitant soigneusement les directives using et en spécifiant explicitement tout ce que vous utilisez (jusqu'à la opérateurs) avec des déclarations using, ou allez-y et commencez using namespace std. Je recommande ce dernier du point de vue de la productivité.

La plupart des manuels c ++ enseignent aux débutants à utiliser l'espace de noms std; propagent-ils de mauvaises pratiques de codage?

Le contraire si vous me demandez, et je crois que Sutter ci-dessus est d'accord.

Maintenant, au cours de ma carrière, j'ai rencontré environ 3 conflits d'espace de noms au total en conséquence directe des directives using dans des bases de code couvrant des dizaines de millions de LOC. Cependant, dans les 3 cas, ils se trouvaient dans des fichiers source qui s'étalaient sur plus de 50 000 lignes de code hérité, initialement écrites en C puis bâtardées en C++, effectuant une liste éclectique massive de fonctions disparates, y compris les en-têtes d'une douzaine de bibliothèques différentes, et ayant une liste épique de #includes qui s'étend sur une page. Malgré le gâchis épique, ils n'ont pas été trop difficiles à réparer car ils ont causé des erreurs de build sur OSX (le seul OS où le code n'a pas pu être construit), pas des bugs d'exécution. N'organisez pas votre code de cette façon cauchemardesque et ça devrait aller.

Cela dit, évitez les deuxusing directives et déclarations dans les fichiers d'en-tête. C'est tout simplement retardé. Mais pour les fichiers source, et en particulier ceux qui n'ont pas une page entière remplie de #include directives, je dirais de ne pas transpirer si vous ne travaillez pas pour Google.

1
user204677