116 votes

Utilisant l'espace de Noms std

Il semble y avoir différents points de vue sur l'utilisation de "l'aide" à l'égard de l'espace de noms std.

Certains disent utiliser ' using namespace std", d'autres disent ne le font pas, mais plutôt préfixe std fonctions pour être utilisé avec ' std::", alors que d'autres disent utiliser quelque chose comme ceci:

using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::vector;

pour toutes les mst fonctions qui doivent être utilisés.

Quels sont les avantages et les inconvénients de chacun? |

141voto

Charles Bailey Points 244082

La plupart C++ utilisateurs sont très satisfaits de la lecture std::string, std::vector, etc. En effet, de voir un raw vector me fait me demander si c'est l' std::vector ou un autre défini par l'utilisateur vector.

using namespace std; Je suis toujours contre. Importations de toutes sortes de noms dans l'espace de noms global et peut causer toutes sortes de la non-évidence les ambiguïtés.

Voici quelques identificateurs communs qui sont dans l' std d'espace de noms: comptage, de tri, de recherche, de l'égalité, de l'inverser. Avoir une variable locale appelée count signifie qu' using namespace std ne sera pas vous permettre d'utiliser count au lieu de std::count.

L'exemple classique d'un indésirable de conflit de nom est quelque chose comme ce qui suit. Imaginez que vous êtes un débutant et ne savent pas à propos de std::count. Imaginez que vous êtes soit à l'aide de quelque chose d'autre en <algorithm> ou il a été tiré par une apparemment sans rapport avec l'en-tête.

#include <algorithm>
using namespace std;

int count = 0;

int increment()
{
    return ++count; // error, identifier count is ambiguous
}

L'erreur est généralement long et froid parce que std::count est un modèle avec de longs les types imbriqués.

C'est OK, parce que std::count va dans l'espace de noms global et la fonction de comptage de la cache.

#include <algorithm>
using namespace std;

int increment()
{
    static int count = 0;
    return ++count;
}

Peut-être un peu surprenant, ce est OK. Les identificateurs importé dans une portée déclarative apparaissent dans la commune de l'espace de noms qui contient à la fois où ils sont définis et où ils sont importés. En d'autres termes, std::count est visible en tant que count en l'espace de noms global, mais seulement à l'intérieur d' increment.

#include <algorithm>

int increment()
{
    using namespace std;
    static int count = 0;
    return ++count;
}

Et pour des raisons similaires, count est ambigu ici. using namespace std ne cause pas de std::count, de masquer l'extérieur count comme on pourrait s'y attendre. L' using namespace règle signifie qu' std::count l'air (en increment de la fonction) comme si elle a été déclarée à la portée globale, c'est à dire à la même portée que d' int count = 0; et donc provoquer l'ambiguïté.

#include <algorithm>

int count = 0;

int increment()
{
    using namespace std;
    return ++count; // error ambiguous
}

45voto

Yacoby Points 29771

À l'exclusion des principes de base (Avoir à ajouter de std:: devant tous les stl objets/fonctions et moins de risque de conflit si vous n'avez pas de "using namespace std')

Il est également intéressant de noter que vous ne devriez jamais mettre

using namespace std

Dans un fichier d'en-tête, comme il peut se propager à tous les fichiers qui comprennent que le fichier d'en-tête, même si ils ne veulent pas utiliser l'espace de nom.

Dans certains cas, il est très avantageux d'utiliser des choses comme

using std::swap

Comme s'il n'y est une version spécialisée de swap, le compilateur utilisera que, sinon, il en sera de retour sur std::swap

Si vous appelez std::swap, vous utilisez toujours la version de base, qui ne fera pas appel de la version optimisée (si elle existe).

28voto

Michael Burr Points 181287

Tout d'abord, la terminologie:

  • aide-déclaration: using std::vector;
  • à l'aide de la directive-: using namespace std;

Je pense que l'utilisation de directives à l'aide sont très bien, tant qu'ils ne sont pas utilisés à la portée globale dans un fichier d'en-tête. Donc, avoir

using namespace std;

dans votre .fichier cpp n'est pas vraiment un problème, et si il s'avère, il est entièrement sous votre contrôle (et il peut même être portée à des blocs particuliers si vous le souhaitez). Je ne vois pas particlar raison d'encombrer le code avec un tas d' std:: qualificatifs - il devient juste un tas de bruit visuel. Toutefois, si vous n'êtes pas à l'aide de tout un tas de noms de l' std d'espace de noms dans votre code, j'ai aussi ne voient aucun problème à laisser de la directive. C'est une tautologie - si la directive n'est pas nécessaire, alors il n'y a pas besoin de l'utiliser.

De même, si vous pouvez vous en tirer avec un peu d' aide de déclarations (au lieu de directives à l'aide) pour spécfiques types dans l' std d'espace de noms, alors il n'y a aucune raison que vous ne devriez pas avoir seulement ceux spefcific noms introduit dans l'espace de noms courant. Par la même occasion, je pense qu'il serait de la folie et de comptabilité tracas d'avoir 25 ou 30 à l'aide de déclarations lorsqu'un seul à l'aide de la directive ferait l'affaire aussi bien.

Il est également bon de garder à l'esprit qu'il ya des moments où vous devez utiliser un aide-déclaration. Reportez-vous à Scott Meyers' "Article 25: Envisager un soutien pour un non-lancer swap" de l'Effective C++, Troisième Édition. Afin d'avoir un générique, basé sur un modèle de fonction utilisation de la "meilleure" méthode d'échange pour un type paramétré, vous avez besoin de faire usage d'une aide-déclaration et de l'argumentation à charge de recherche (aka ADL ou Koenig de recherche):

template< typename T >
void foo( T& x, T& y)
{
    using std::swap;     // makes std::swap available in this function

    // do stuff...

    swap( x, y);         // will use a T-specific swap() if it exists,
                         //  otherwise will use std::swap<T>()

    // ...
 }

Je pense que nous devrions nous pencher sur la commune de locutions pour différentes langues, qui font un usage important des espaces de noms. Par exemple, Java et C# utiliser des espaces de noms dans une large mesure (sans doute plus que le C++). La façon la plus courante de noms dans les espaces de noms sont utilisés dans ces langues est en les mettant à la portée actuelle en masse avec l'équivalent d'un à l'aide de la directive. Ce n'est pas une cause répandue de problèmes, et les rares fois où c'est un problème sont traités sur une "exception" en traitant avec les noms en question via complet des noms ou par aliasing tout comme peut être fait en C++.

Herb Sutter et Andrei Alexandrescu ont ceci à dire dans "Item 59: Ne pas écrire de l'usage de l'espace de noms dans un fichier d'en-tête ou devant un #include" de leur livre, C++ Normes de Codage: 101 Règles, des lignes Directrices et des Pratiques Exemplaires à:

En bref: Vous pouvez et devez utiliser l'espace de noms à l'aide des déclarations et des directives généreusement dans vos fichiers de mise en œuvre après l' #include directives et de se sentir bien à ce sujet. En dépit des affirmations contraires, de l'espace de noms à l'aide de déclarations et directives ne sont pas mauvais et ils ne sont pas à l'encontre du but d'espaces de noms. Plutôt, ils sont ce qui rend les espaces de noms utilisable.

Stroupstrup est souvent cité comme disant, "Ne pas polluer l'espace de noms global", dans Le Langage de Programmation C++, Troisième Édition". Il n'est, en fait, dire que (C. 14[15]), mais se réfère au chapitre C. 10.1 où il dit:

Un aide-déclaration ajoute un nom à un une portée locale. Un aide-directivene pas; simplement, il rend noms accessible dans le cadre dans lequel elles ont été déclarés. Par exemple:

namespaceX {
    int i , j , k ;
}

int k ;
void f1()
{
    int i = 0 ;

    using namespaceX ; // make names from X accessible

    i++; // local i
    j++; // X::j
    k++; // error: X::k or global k ?

    ::k ++; // the global k

    X::k ++; // X's k
}

void f2()
{
    int i = 0 ;

    using X::i ; // error: i declared twice in f2()
    using X::j ;
    using X::k ; // hides global k

    i++;
    j++; // X::j
    k++; // X::k
}

Un déclarés localement nom (déclarée soit par simple déclaration ou par une aide-déclaration) se cache non déclarations du même nom, et tout illicite les surcharges du nom sont détecté au moment de la déclaration.

Remarque l'erreur d'ambiguïté pour k++dans f1(). Mondial les noms ne sont pas donnés la préférence sur les noms d'espaces de noms accessible dans la portée globale. Cela permet une grande protection contre les chocs, les collisions de noms, et – important – s'assure qu'il y a pas d'avantages polluer l'espace de noms global.

Quand les bibliothèques déclarant beaucoup de noms sont accessibles par l'intermédiaire de directives à l'aide, il est important l'avantage que les affrontements de la partie inutilisée des noms ne sont pas considérées comme des erreurs.

...

J'espère voir une diminution radicale l'utilisation de noms globaux dans les nouvelles les programmes utilisant les espaces de noms par rapport à traditionnelle programmes C et C++. L' règles pour les espaces de noms ont été spécifiquement conçu pour donner à aucun des avantages d'une ‘paresseux" utilisateur de noms globaux sur quelqu'un qui prend soin de ne pas polluer la portée globale.

Et comment a-t-on le même avantage que d'un "paresseux utilisateur de noms globaux'? En profitant de l'aide de la directive, qui en toute sécurité rend les noms dans un espace de noms disponibles à l'étendue actuelle.

Noter qu'il y a une distinction - noms dans l' std de l'espace de noms à la disposition d'un champ avec la bonne utilisation de l'aide de la directive (en plaçant la directive après l' #includes) ne pas polluer l'espace de noms global. C'est juste faire ces noms facilement, et avec une protection continue contre les affrontements.

17voto

AProgrammer Points 31212

Ne jamais utiliser à l'aide de l'espace de noms à la portée globale dans un fichier d'en-tête. Qui peut conduit à des conflits et la personne en charge du dossier où le conflit s'affiche n'a aucun contrôle sur la cause.

Dans la mise en œuvre de fichier, les choix sont beaucoup moins bien coupé.

  • Mettre un using namespace std apporte tous les symboles des espaces de noms. Cela peut être problématique, car presque pas de corps de connaître tous les symboles qui y sont (donc avoir une politique sans conflit est impossible à appliquer dans la pratique), sans parler de la signification des symboles qui seront ajoutés. Et le C++ standard permet un en-tête pour ajouter des symboles à partir d'autres en-têtes (le C ne permet pas que). Il peut encore bien fonctionner dans la pratique, pour simplifier l'écriture contrôlée de cas. Et si une erreur se produit, il est détecté dans le fichier qui a le problème.

  • Mettant en utilisant std::nom, a l'avantage de la simplicité de l'écriture, sans le risque d'importer des symboles inconnus. Le coût est que vous devez importer explicitement voulions tous les symboles.

  • Explicitement de qualification ajouter un peu fouillis, mais je pense que c'est le moins de mal un peu de pratique.

Dans mon projet, j'utilise explicite de qualification pour tous les noms, j'accepte l'utilisation de std::nom, je lutte contre using namespace std (nous avons un interpréteur lisp qui a son propre type de liste et donc le conflit est une chose sûre).

Pour d'autres espaces de noms, vous devez aussi prendre en compte les conventions de nommage utilisées. Je sais que d'un projet d'utilisation de l'espace de noms (pour le versionnage) et le préfixe des noms. Faire un using namespace X puis est presque sans risque et ne pas le faire conduit à stupides à la recherche de code PrefixNS::pfxMyFunction(...).

Il y a certains cas où vous souhaitez importer les symboles. std::swap est le cas le plus courant: vous importez des std::swap et ensuite utiliser swap non qualifiés. Argument dépendante de recherche va trouver une swap dans l'espace de noms du type si il y en a un et tomber en arrière pour le modèle standard si il n'y a aucun.


Edit:

Dans les commentaires, Michael Burr se demande si les conflits se produisent dans le monde réel. Ici est un vrai exemple. Nous avons une extension de la langue est un dialecte de lisp. Notre interprète a un fichier include, lisp.h contenant

typedef struct list {} list;

Nous avons dû intégrer et de s'adapter un peu de code (que je vais nommer "moteur") qui ressemblait à ceci:

#include <list>
...
using std::list;
...
void foo(list const&) {}

Nous avons donc modifié comme ceci:

#include <list>

#include "module.h"
...
using std::list;
...
void foo(list const&) {}

Bon. Tout ce travail. Quelques mois plus tard, le module".h" a été modifié pour inclure "liste.h". Les tests passés. "module" n'avait pas modifié d'une manière qui porte atteinte à sa ABI, de sorte que le "moteur" de la bibliothèque pourrait être utilisé sans re-compilation de ses utilisateurs. Les tests d'intégration ont été OK. Nouveau "module" publié. Prochaine compilation de casse moteur lors de son code n'a pas à être modifié.

4voto

Tadeusz Kopec Points 7625

Les deux

using std::string;

et

using namespace std;

ajoutez des symboles (un ou beaucoup de) à l'espace de noms global. Et ajouter des symboles à l'espace de noms global est quelque chose que vous devriez jamais le faire dans les fichiers d'en-tête. Vous n'avez aucun contrôle qui comprend votre en-tête, il y a beaucoup de têtes qui comprennent les autres en-têtes (et les en-têtes qui incluent des en-têtes qui incluent des en-têtes, etc...).

Dans la mise en œuvre (.rpc) des fichiers, c'est à vous (seulement n'oubliez pas de le faire après toutes les directives #include). Vous pouvez rompre uniquement code dans ce fichier spécifique, de sorte qu'il est plus facile de gérer et de trouver la raison de conflits de nom. Si vous préférez utiliser std:: (ou tout autre préfixe, il peut y avoir plusieurs espaces de noms dans votre projet) avant indentifiers, c'est OK. Si vous aimez ajouter les identifiants que vous utilisez pour l'espace de noms global, c'est OK. Si vous souhaitez apporter de l'ensemble de l'espace de noms sur votre tête :-), c'est à vous. Alors que les effets sont limités à une seule unité de compilation, c'est acceptable.

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