Il semble y avoir des vues différentes sur l'utilisation de «using» par rapport à l'espace de noms std.
Certains disent utiliser ' using namespace std
', d'autres disent ne pas le faire mais préfixer les fonctions std qui doivent être utilisées avec ' std::
' tandis 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 fonctions std à utiliser.
Quels sont les avantages et les inconvénients de chacun?
c++
namespaces
paoloricardo
la source
la source
Réponses:
La plupart des utilisateurs de C ++ sont assez heureux de lire
std::string
,std::vector
etc. En fait, voir un rawvector
me fait me demander s'il s'agit dustd::vector
ou d'un autre défini par l'utilisateurvector
.Je suis toujours contre l'utilisation
using namespace std;
. Il importe toutes sortes de noms dans l'espace de noms global et peut provoquer toutes sortes d'ambiguïtés non évidentes.Voici quelques identifiants courants qui se trouvent dans l'
std
espace de noms: compter, trier, trouver, égal, inversé. Avoir une variable locale appeléecount
signifie queusing namespace std
vous ne pourrez pas l'utiliser à lacount
place destd::count
.L'exemple classique d'un conflit de nom indésirable est quelque chose comme le suivant. Imaginez que vous êtes un débutant et que vous ne savez rien
std::count
. Imaginez que vous utilisiez quelque chose d'autre<algorithm>
ou qu'il ait été attiré par un en-tête apparemment sans rapport.L'erreur est généralement longue et peu conviviale car il
std::count
s'agit d'un modèle avec quelques types imbriqués longs.C'est bien, car il
std::count
entre dans l'espace de noms global et le nombre de fonctions le cache.Peut-être un peu étonnamment, c'est OK. Les identificateurs importés dans une portée déclarative apparaissent dans l'espace de noms commun qui englobe à la fois l'endroit où ils sont définis et l'endroit où ils sont importés. En d'autres termes,
std::count
est visible commecount
dans l'espace de noms global, mais uniquement à l'intérieurincrement
.Et pour des raisons similaires,
count
est ambigu ici.using namespace std
ne cause passtd::count
, cachez l'extérieurcount
comme on pourrait s'y attendre. Lausing namespace
règle signifie qu'ellestd::count
ressemble (dans laincrement
fonction) comme si elle avait été déclarée à la portée globale, c'est-à-dire à la même portée queint count = 0;
et donc provoquant l'ambiguïté.la source
using std::xxx;
. Cela necopy
pollue pas les espaces de noms, l'écriture du code sera plus courte et je pense que c'est beaucoup plus lisible questd::copy
.Excluant les bases (devoir ajouter std :: en face de tous les objets / fonctions stl et moins de risque de conflit si vous n'avez pas 'using namespace std')
Il convient également de noter que vous ne devez jamais mettre
Dans un fichier d'en-tête, car il peut se propager à tous les fichiers qui incluent ce fichier d'en-tête, même s'ils ne souhaitent pas utiliser cet espace de noms.
Dans certains cas, il est très avantageux d'utiliser des choses comme
Comme s'il y avait une version spécialisée de swap, le compilateur l'utilisera, sinon il se rabattra
std::swap
.Si vous appelez
std::swap
, vous utilisez toujours la version de base, qui n'appellera pas la version optimisée (si elle existe).la source
using std::swap
(qui est la seule chose que j'utilise jamais).u n s
peut se propager. Juste pour noter qu'il peut également se frayer un chemin dans des en-têtes correctement construits: ils doivent juste être inclus après un en-tête non autorisé.swap
oumove
(ouhash
,less
etc.), vous devriez de toute façon intégrer cette spécialisationnamespace std
. Par exemple:namespace std {template<> class hash<X> {public: size_t operator()(const X&) const};} class X: {friend size_t std::hash<X>::operator()(const X&)};
Tout d'abord, un peu de terminologie:
using std::vector;
using namespace std;
Je pense que l'utilisation de directives d'utilisation est très bien, tant qu'elles ne sont pas utilisées à l'échelle globale dans un fichier d'en-tête. Donc avoir
dans votre fichier .cpp n'est pas vraiment un problème, et si cela s'avère être, c'est complètement sous votre contrôle (et il peut même être étendu à des blocs particuliers si vous le souhaitez). Je ne vois aucune raison particulière d'encombrer le code avec une multitude de
std::
qualificatifs - cela devient juste un tas de bruit visuel. Cependant, si vous n'utilisez pas tout un tas de noms de l'std
espace de noms dans votre code, je ne vois pas non plus de problème à laisser de côté la directive. C'est une tautologie - si la directive n'est pas nécessaire, alors il n'est pas nécessaire de l'utiliser.De même, si vous pouvez vous en tirer avec quelques déclarations using (au lieu de directives using ) pour des types spécifiques dans l'
std
espace de noms, alors il n'y a aucune raison pour laquelle vous ne devriez pas avoir juste ces noms spécifiques dans l'espace de noms actuel. De la même manière, je pense que ce serait fou et compliqué d'avoir 25 ou 30 déclarations d'utilisation alors qu'une seule directive d'utilisation ferait tout aussi bien l'affaire.Il est également bon de garder à l'esprit qu'il y a des moments où vous devez utiliser une déclaration using. Reportez-vous à «Item 25: Consider support for a non-throwing swap» de Scott Meyers, Third Edition. Pour qu'une fonction générique et basée sur un modèle utilise la `` meilleure '' méthode d'échange pour un type paramétré, vous devez utiliser une déclaration d'utilisation et une recherche dépendante de l'argument (également appelée ADL ou Koenig lookup):
Je pense que nous devrions examiner les expressions idiomatiques communes à divers langages qui utilisent de manière significative les espaces de noms. Par exemple, Java et C # utilisent les espaces de noms dans une large mesure (sans doute plus que C ++). La manière la plus courante d'utiliser les noms dans les espaces de noms dans ces langages est de les intégrer en masse dans la portée actuelle avec l'équivalent d'une directive using. Cela ne pose pas de problèmes très répandus, et les rares fois où c'est un problème sont traités sur une base «d'exception» en traitant les noms en question via des noms complets ou par alias - tout comme cela peut être fait en C ++.
Herb Sutter et Andrei Alexandrescu ont ceci à dire dans «Point 59: N'écrivez pas les utilisations de l'espace de noms dans un fichier d'en-tête ou avant un #include» de leur livre, Normes de codage C ++: 101 règles, directives et meilleures pratiques:
Stroupstrup est souvent cité comme disant: "Ne polluez pas l'espace de noms global", dans "The C ++ Programming Language, Third Edition". Il dit effectivement cela (C.14 [15]), mais se réfère au chapitre C.10.1 où il dit:
Et comment avoir le même avantage qu'un «utilisateur paresseux de noms globaux»? En tirant parti de la directive using, qui rend en toute sécurité les noms d'un espace de noms disponibles pour la portée actuelle.
Notez qu'il y a une distinction - les noms dans l'
std
espace de noms mis à disposition d'une portée avec l'utilisation correcte d'une directive using (en plaçant la directive après le#includes
) ne polluent pas l'espace de noms global. Il s'agit simplement de rendre ces noms disponibles facilement et avec une protection continue contre les affrontements.la source
std::
qualificatifs n'encombrent pas le code - il existe d'autres moyens d'éviter cela (les déclarations en utilisant ou les typedefs font généralement l'affaire).using namespace std;
directive " " ne vous empêche pas de déclarer votre identifiant naturel 'list
' - c'est juste que si vous le faites, vous ne pouvez pas utilisation plus longuestd::list
sans le qualifier. Ce n'est pas différent que s'il n'y a pas deusing namespace std;
directive " ". Ou est-ce que je manque quelque chose?N'utilisez jamais l'utilisation de l'espace de noms à portée globale dans un fichier d'en-tête. Cela peut conduire à un conflit et la personne en charge du dossier où apparaît le conflit n'a aucun contrôle sur la cause.
Dans le dossier d'implémentation, les choix sont beaucoup moins bien découpés.
Mettre un espace de noms using std apporte tous les symboles de ces espaces de noms. Cela peut être gênant car presque aucun organisme ne connaît tous les symboles qui sont là (donc avoir une politique de non-conflit est impossible à appliquer dans la pratique) sans parler des symboles qui seront ajoutés. Et le standard C ++ permet à un en-tête d'ajouter des symboles d'autres en-têtes (celui en C ne le permet pas). Cela peut encore bien fonctionner en pratique pour simplifier l'écriture en cas contrôlé. Et si une erreur se produit, elle est détectée dans le fichier qui présente le problème.
Mettre en utilisant std :: name; présente l'avantage de la simplicité d'écriture sans risque d'importer des symboles inconnus. Le coût est que vous devez importer explicitement tous les symboles voulus.
Les qualifications explicites ajoutent un peu de fouillis, mais je pense que c'est le moins ennuyeux de la pratique.
Dans mon projet, j'utilise une qualification explicite pour tous les noms, j'accepte d'utiliser std :: name, je lutte contre l'utilisation de 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 les autres espaces de noms, vous devez également prendre en compte les conventions de dénomination utilisées. Je connais un projet qui utilise un espace de noms (pour la version) et un préfixe sur les noms. Faire un
using namespace X
alors est presque sans risque et ne pas le faire conduit à un code stupidePrefixNS::pfxMyFunction(...)
.Dans certains cas, vous souhaitez importer les symboles. std :: swap est le cas le plus courant: vous importez std :: swap, puis utilisez swap non qualifié. La recherche dépendante de l'argument trouvera un swap adéquat dans l'espace de noms du type s'il y en a un et retournera au modèle standard s'il n'y en a pas.
Éditer:
Dans les commentaires, Michael Burr se demande si les conflits se produisent dans le monde réel. Voici un vrai exemple en direct. Nous avons une langue d'extension avec un dialecte lisp. Notre interpréteur a un fichier d'inclusion, lisp.h contenant
Nous avons dû intégrer et adapter du code (que je nommerai "engine") qui ressemblait à ceci:
Nous avons donc modifié comme ceci:
Bien. Tout fonctionne. Quelques mois plus tard, "module.h" a été modifié pour inclure "list.h". Les tests ont réussi. "module" n'avait pas été modifié d'une manière qui affectait son ABI, donc la bibliothèque "engine" pouvait être utilisée sans recompiler ses utilisateurs. Les tests d'intégration étaient OK. Nouveau "module" publié. La prochaine compilation du moteur est tombée en panne lorsque son code n'a pas été modifié.
la source
Si vous n'avez pas de risque de conflits de noms dans votre code avec std et d'autres bibliothèques, vous pouvez utiliser:
Mais si vous voulez connaître précisément la dépendance de votre code pour la documentation ou s'il y a un risque de conflits de noms, utilisez l'inverse:
La troisième solution, n'utilisez pas ces solutions et écrivez std :: avant chaque utilisation dans le code vous apporte plus de sécurité mais, peut-être un peu de lourdeur dans le code ...
la source
Tous les deux
et
ajoutez quelques symboles (un ou plusieurs) à l'espace de noms global. Et l'ajout de symboles à l'espace de noms global est quelque chose que vous ne devriez jamais faire dans les fichiers d'en-tête. Vous n'avez aucun contrôle qui inclura votre en-tête, il y a beaucoup d'en-têtes qui incluent d'autres en-têtes (et des en-têtes qui incluent des en-têtes qui incluent des en-têtes et ainsi de suite ...).
Dans les fichiers d'implémentation (.cpp), c'est à vous (n'oubliez pas de le faire après toutes les directives #include). Vous ne pouvez casser que le code de ce fichier spécifique, il est donc plus facile à gérer et à découvrir la raison du conflit de nom. Si vous préférez utiliser std :: (ou tout autre préfixe, il peut y avoir de nombreux espaces de noms dans votre projet) avant les indentificateurs, c'est OK. Si vous souhaitez ajouter des identificateurs que vous utilisez à l'espace de noms global, c'est OK. Si vous voulez mettre tout l'espace de noms sur votre tête :-), c'est à vous de décider. Bien que les effets soient limités à une seule unité de compilation, c'est acceptable.
la source
Pour moi, je préfère utiliser
::
quand c'est possible.Je déteste écrire:
J'espère qu'avec C ++ 0x j'écrirais ceci:
Si l'espace de noms est très long,
la source
++i
, pasi++
parce que, s'il est même défini, crée une copie temporaire inutile de l'itérateur.Vous ne devez jamais être
using namespace std
à la portée de l'espace de noms dans un en-tête. De plus, je suppose que la plupart des programmeurs se demanderont quand ils verrontvector
oustring
nonstd::
, donc je pense que ce n'est pasusing namespace std
mieux. C'est pourquoi je soutiens qu'il n'y aura jamaisusing namespace std
du tout.Si vous vous sentez obligé, ajoutez local en utilisant des déclarations comme
using std::vector
. Mais demandez-vous: qu'est-ce que cela vaut? Une ligne de code est écrite une fois (peut-être deux), mais elle est lue dix, cent ou mille fois. L'effort de frappe économisé en ajoutant une déclaration ou une directive using est marginal par rapport à l'effort de lecture du code.Dans cet esprit, dans un projet il y a dix ans, nous avons décidé de qualifier explicitement tous les identificateurs avec leurs noms d'espace de noms complets. Ce qui semblait gênant au début est devenu une routine en deux semaines. Désormais, dans tous les projets de toute l'entreprise, personne n'utilise plus de directives ou de déclarations. (À une exception près, voir ci-dessous.) En regardant le code (plusieurs MLoC) après dix ans, j'ai l'impression que nous avons pris la bonne décision.
J'ai constaté que généralement, ceux qui s'opposent à l'interdiction
using
ne l'ont généralement pas essayé pour un projet. Ceux qui ont essayé, trouvent souvent mieux que d'utiliser des directives / déclarations après un temps très court.Remarque: La seule exception est
using std::swap
ce qui est nécessaire (en particulier dans le code générique) pour récupérer les surchargesswap()
qui ne peuvent pas être placées dans l'std
espace de noms (car nous ne sommes pas autorisés à placer des surcharges destd
fonctions dans cet espace de noms).la source
std
, mais pas la surcharge. Désolé pour ce brainfart. Je vais corriger le message.using namespace
directive était non plus de faire de la dactylographie ; c'était plutôt pour faciliter la lecture , car, comme vous le dites, ce code devra être lu des dizaines, des centaines ou des milliers de fois. Et pour certaines personnes, il lit beaucoup plus facilement avec moins d'std::
encombrement. Mais cela revient probablement à la capacité perceptive personnelle; certaines personnes filtrentstd::
ou même en ont besoin pour se guider (comme des empattements), d'autres trébuchent dessus et se sentent comme sur une route cahoteuse.Les espaces de noms conservent le code contenu pour éviter la confusion et la pollution des signatures de fonction.
Voici une démonstration complète et documentée de l ' utilisation correcte de l' espace de noms :
Production:
la source
using namespace std
importe le contenu de l'std
espace de noms dans celui en cours. Ainsi, l'avantage est que vous n'aurez pas à taperstd::
devant toutes les fonctions de cet espace de noms. Cependant, il peut arriver que vous ayez différents espaces de noms qui ont des fonctions du même nom. Ainsi, vous risquez de ne plus appeler celui que vous souhaitez.Spécifier manuellement ceux dans lesquels vous souhaitez importer
std
empêche que cela se produise, mais peut entraîner une longue liste d'utilisation au début de votre fichier, que certains développeurs trouveront moche;)!Personnellement, je préfère spécifier l'espace de noms à chaque fois que j'utilise une fonction, sauf lorsque l'espace de noms est trop long, auquel cas j'en mets en utilisant au début du fichier.
EDIT: comme indiqué dans une autre réponse, vous ne devriez jamais mettre un
using namespace
dans un fichier d'en-tête, car il se propagera à tous les fichiers, y compris cet en-tête, et pourrait donc produire un comportement indésirable.EDIT2: corrigé ma réponse, grâce au commentaire de Charles.
la source
using namespace std;
importe le contenu de l'std
espace de noms dans l'espace de noms global. Cela ne change pas l'espace de noms par défaut. Définir quelque chose dans l'espace de noms global après unusing namespace std
ne le mettra pas comme par magie dans l'std
espace de noms.Tout comme en Java où vous pouvez utiliser soit inclure java.util. * Ou simplement sélectionner chaque classe individuellement, cela dépend du style. Notez que vous n'en voulez pas
using namespace std
au début de votre fichier / portée étendue car vous polluerez l'espace de noms et aurez peut-être des conflits, éliminant le point des espaces de noms. Mais si vous avez une fonction qui utilise beaucoup de STL, elle encombre le code pour avoir un fouillis de syntaxe de préfixage dans votre logique et vous devriez probablement envisager d'utiliser soitusing namespace std
(lorsque vous utilisez une variété de classes) soit individuelleusing
s (lorsque vous utilisez quelques cours souvent).la source
Cette discussion sera vivante tant que l'EDI avec lequel vous travaillez n'est pas assez flexible pour afficher ou masquer les informations exactes dont vous avez besoin.
C'est parce que l'apparence que vous voulez de votre code dépend de la tâche à accomplir.
Lors de la création de mon code source, je préfère voir exactement quelle classe j'utilise: est-ce
std::string
, ou leBuzFlox::Obs::string
classe?Lors de la conception du flux de contrôle, je ne suis même pas intéressé par les types de variables, mais je veux me concentrer sur les
if
's etwhile
' s etcontinue
les.Alors voici mon conseil:
En fonction de l'audience de votre code et de la puissance de vos outils, choisissez la manière qui lit le plus facilement ou qui donne le plus d'informations.
la source
Il existe plusieurs façons de résoudre ce problème.
Premièrement: utilisez comme ce que vous avez fait.
Deuxièmement: faire
namespace S = std;
, réduire 2 caractères.Troisièmement: utiliser
static
.Quatrièmement: n'utilisez pas de noms qui
std
utilisent.la source
La seule raison de ne pas utiliser std :: est que vous pourriez, en théorie, réimplémenter vous-même toutes les fonctions STL. Ensuite, vos fonctions pourraient passer de l'utilisation de std :: vector à my :: vector sans changer le code.
la source
Pourquoi pas par exemple
au lieu du lourd
Je trouve cela beaucoup plus lisible et c'est ma norme de codage.
Vous pouvez même l'utiliser pour inclure des informations sémantiques pour le lecteur. Par exemple, considérons les prototypes de fonction
lesquels la valeur de retour?
Et plutôt
la source