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

15

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

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

Quelle est la voie recommandée? std::cout<<? La plupart des manuels c ++ enseignent aux débutants avec une using namespace std;mauvaise pratique de codage?

Lord Loh.
la source

Réponses:

18

En lisant la norme Google, vous ne pouvez utiliser la using namespace foo;directive 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 ensuiteusing 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 que std :: any 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.

Michael Mathews
la source
1
Merci! C'est vraiment utile. Vous avez non seulement expliqué pourquoi il est mauvais avec de beaux exemples, mais aussi souligné des solutions avec de beaux exemples. :-)
Lord Loh.
1
BTW: L'utilisation std::endlpour le vidage explicite sur stdout/ stderrest normalement assez superflue, ces flux sont liés à stdout/ de stderrtoute façon. Cela ralentit même un peu les choses.
Déduplicateur
8

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.

Tarte aux pommes
la source
Je suppose que cela signifie que je devrais utiliser std::max()le préfixe d'espace de nom. Ou je me trompe?
Lord Loh.
3
Cela signifie que si vous mettez "using namespace std;" dans votre code, vous obtiendrez des erreurs si vous définissez votre propre fonction max (ou tout autre nom déjà défini dans l'espace de noms std)
Chewy Gumball
1
Cela signifie simplement que vous devez être prudent avec les usingdirectives car dans ce cas, cela casserait votre fonction max () si vous en aviez défini une et inclus <algorithme>. C'est un cas simple mais vous ne savez jamais ce que vous pourriez casser. Vous auriez besoin de connaître la bibliothèque entière pour être sûr de ne pas la casser, mais vous ne pouvez pas savoir si votre code se briserait (c'est-à-dire collision de noms) à l'avenir.
ApplePie
6

Citant le lien que vous fournissez:

Vous pouvez utiliser une déclaration using 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'utiliser 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.

Basilevs
la source
Nous avons les mêmes normes. Certaines de nos personnes typeront localement un long espace de noms. par exemple typedef foolicious :: barlicious fb; fb :: boire d;
Michael Mathews
1

ils ne recommandent pas d'utiliser la fonction namespace ornamespace: function` - si je ne l'ai pas mal interprétée.

Tu l'as fait. La recommandation ne s'applique qu'à la using namespacedirective (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.

H2CO3
la source
1

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 usingmot - clé et les descriptions d' namespaceutilisation, même s'ils essaient de l'apprendre en recherchant la référence, car la déclaration et la directive se lisent quelque peu équivalentes, 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 usingmot-clé permet d'éviter ces inconvénients de l'espace de noms. Étant donné qu'il usingfonctionne au niveau du compilateur (ce n'est pas une macro), son effet dure pour toute l'étendue dans laquelle il est utilisé. C'est pourquoi le style Google limite son utilisation à des étendues bien définies, c'est-à-dire des classes dans des fichiers d'en-tête ou des fonctions dans des fichiers cpp.

... bien sûr, il y a une différence entre utiliser 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.

Loup
la source
1

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.

C'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 devez utiliser l' espace de noms en utilisant des déclarations et directives généreusement dans vos dossiers de mise en œuvre après les directives #include et se sentir bien à ce sujet. Malgré les affirmations répétées du contraire, les espaces de noms utilisant des déclarations et des directives ne sont pas mauvais et ils ne vont pas à l'encontre de l'objectif des espaces de noms. C'est plutôt ce qui rend les espaces de noms utilisables .

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 rare sur le plan astronomique en évitant soigneusement les usingdirectives et en spécifiant explicitement chaque chose que vous utilisez (jusqu'aux opérateurs) avec des usingdéclarations, 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 le 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 de usingdirectives 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 #includescela s'étalant sur une page. Malgré le désordre é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 using directives et les 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 #includedirectives, je dirais ne pas transpirer si vous ne travaillez pas pour Google.


la source