Utilisation de l'espace de noms std

110

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?

paoloricardo
la source

Réponses:

131

La plupart des utilisateurs de C ++ sont assez heureux de lire std::string, std::vectoretc. En fait, voir un raw vectorme fait me demander s'il s'agit du std::vectorou d'un autre défini par l'utilisateur vector.

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' stdespace de noms: compter, trier, trouver, égal, inversé. Avoir une variable locale appelée countsignifie que using namespace stdvous ne pourrez pas l'utiliser à la countplace de std::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.

#include <algorithm>
using namespace std;

int count = 0;

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

L'erreur est généralement longue et peu conviviale car il std::counts'agit d'un modèle avec quelques types imbriqués longs.

C'est bien, car il std::countentre dans l'espace de noms global et le nombre de fonctions le cache.

#include <algorithm>
using namespace std;

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

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::countest visible comme countdans l'espace de noms global, mais uniquement à l'intérieur increment.

#include <algorithm>

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

Et pour des raisons similaires, countest ambigu ici. using namespace stdne cause pas std::count, cachez l'extérieur countcomme on pourrait s'y attendre. La using namespacerègle signifie qu'elle std::countressemble (dans la incrementfonction) comme si elle avait été déclarée à la portée globale, c'est-à-dire à la même portée que int count = 0;et donc provoquant l'ambiguïté.

#include <algorithm>

int count = 0;

int increment()
{
    using namespace std;
    return ++count; // error ambiguous
}
CB Bailey
la source
21
mais il tape tellement plus facilement sans le préfixe std ::!
xtofl
69
@xtofl: Non, ce n'est pas le cas. Cinq caractères ne sont pas très pertinents lors de la saisie, mais ces cinq caractères peuvent être très pertinents lors de la lecture. Et la facilité de lecture compte beaucoup plus que la facilité de saisie du code source, car le code est beaucoup plus lu qu'écrit.
sbi
3
Vous pouvez ajouter que l'instruction using se comporte correctement avec les règles de portée.
Martin York
2
@Martin York: mise à jour avec des exemples illustrant les règles de cadrage. @Michael Burr: Ce n'est sans doute pas si mal, ce que je n'aime vraiment pas, c'est là où les messages d'erreur pour de simples erreurs deviennent beaucoup plus difficiles à interpréter, ou là où ils ne se produisent pas du tout. Par exemple, si une fonction est considérée comme étant dans la portée, mais ne l'est pas et qu'une fonction std :: function l'est, plutôt que d'obtenir une erreur utile `` identifiant non reconnu '', vous vous retrouvez souvent avec un argument plus obscur `` impossible de convertir '' Erreur de style X 'ou' impossible de générer la fonction à partir du modèle '. Le pire est si une fonction incorrecte est appelée silencieusement. C'est rare, mais cela arrive.
CB Bailey
5
Eh bien, je suis surpris que personne n'ait discuté de l'option using std::xxx;. Cela ne copypollue pas les espaces de noms, l'écriture du code sera plus courte et je pense que c'est beaucoup plus lisible que std::copy.
legends2k
41

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

using namespace std

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

using std::swap

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).

Yacoby
la source
10
+1 pour mentionner using std::swap(qui est la seule chose que j'utilise jamais).
sbi
1
+1 pour mentionner que u n speut 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é.
quamrana
1
Mais si vous définissez une spécialisation swapou move(ou hash, lessetc.), vous devriez de toute façon intégrer cette spécialisation namespace 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&)};
AJMansfield
28

Tout d'abord, un peu de terminologie:

  • using-declaration : using std::vector;
  • using-directive : 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

using namespace std;

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' stdespace 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' stdespace 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):

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 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:

En bref: vous pouvez et devez utiliser l'espace de noms en utilisant des déclarations et des directives libéralement dans vos fichiers d'implémentation après les #includedirectives et vous en sentirez bien. Malgré des 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.

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:

Une déclaration d'utilisation ajoute un nom à une portée locale. Une directive d'utilisation ne le fait pas; il rend simplement les noms accessibles dans la portée dans laquelle ils 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 nom déclaré localement (déclaré soit par une déclaration ordinaire soit par une déclaration d'utilisation) masque les déclarations non locales du même nom, et toute surcharge illégale du nom est détectée au point de déclaration.

Notez l'erreur d'ambiguïté pour k++in f1(). Les noms globaux n'ont pas de préférence sur les noms d'espaces de noms rendus accessibles dans la portée globale. Cela fournit une protection significative contre les conflits de noms accidentels et - surtout - garantit qu'il n'y a aucun avantage à tirer de la pollution de l'espace de noms global.

Lorsque les bibliothèques déclarant de nombreux noms sont rendues accessibles via des directives using, c'est un avantage significatif que les conflits de noms inutilisés ne sont pas considérés comme des erreurs.

...

J'espère voir une diminution radicale de l'utilisation des noms globaux dans les nouveaux programmes utilisant des espaces de noms par rapport aux programmes traditionnels C et C ++. Les règles pour les espaces de noms ont été spécifiquement conçues pour ne donner aucun avantage à un utilisateur «paresseux» de noms globaux par rapport à quelqu'un qui prend soin de ne pas polluer la portée globale.

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' stdespace 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.

Michael Burr
la source
En ce qui concerne votre dernier point: Java et C # ont également des espaces de noms beaucoup plus soignés. Si tout dans la BCL vivait dans System, "utiliser System" causerait autant de problèmes que "utiliser l'espace de noms std".
Jeff Hardy
Mais les programmes Java et C # que je vois apportent généralement tous les espaces de noms qu'ils utilisent - pas seulement "System" (ou son équivalent). Donc, au lieu d'une seule directive using qui ramène tous les noms utilisés, il y en a 5 ou 10 qui font plus ou moins la même chose. Aussi, fait "using namespace std;" vraiment causer autant de problèmes?
Michael Burr
Le problème est que std a trop de noms communs et que l'inclusion d'un en-tête standard peut inclure tous les autres. Nous n'avons pas un bon contrôle sur ce qui est importé, il y a trop de risques. Je ne connais pas assez Java et C #, mais je connais Ada qui a un système de modules bien meilleur que C ++ et où l'importation de noms est généralement mal vue. En général, c'est d'abord une question de convention de dénomination (j'ai vu des gens utiliser le préfixe ainsi que l'espace de nom, et l'importation n'a pas de sens) puis de style.
AProgrammer
1
Je ne suis toujours pas convaincu que ce soit un problème réel. Je vois des directives d'utilisation utilisées tout le temps sans inconvénients graves. Là encore, je n'ai aucun problème à ne pas les utiliser. Je préfère simplement que les 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).
Michael Burr
1
@AProgrammer: vous dites, "list est un identifiant naturel pour identifier la liste dans un interpréteur lisp" - mais avoir la 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 longue std::listsans le qualifier. Ce n'est pas différent que s'il n'y a pas de using namespace std;directive " ". Ou est-ce que je manque quelque chose?
Michael Burr
17

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 Xalors est presque sans risque et ne pas le faire conduit à un code stupide PrefixNS::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

typedef struct list {} list;

Nous avons dû intégrer et adapter du code (que je nommerai "engine") 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&) {}

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é.

Programmeur
la source
1
L'un des cas contrôlés où je pense que l'utilisation de l'espace de noms est acceptable est la publication de code. La simplification facilite la mise en page de la page et aide à se concentrer sur le point exposé. L'inconvénient est qu'il ne montre pas vraiment une bonne pratique, donc je ne l'utiliserais pas dans des livres pour débutants.
AProgrammer
1
Je pense que taper std :: est un petit prix à payer pour la clarté
paoloricardo
4
@paoloricardo: D'un autre côté, je pense qu'avoir std :: apparaître partout est un encombrement visuel inutile.
Michael Burr
1
@Michael: vous payez votre argent et vous faites votre choix!
paoloricardo
2
Merci d'avoir pris le temps d'ajouter les détails du problème que vous avez rencontré.
Michael Burr
4

Si vous n'avez pas de risque de conflits de noms dans votre code avec std et d'autres bibliothèques, vous pouvez utiliser:

using namespace std;

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:

using std::string;
using std::cout;

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 ...

Matthieu
la source
4

Tous les deux

using std::string;

et

using namespace std;

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.

Tadeusz Kopec
la source
3

Pour moi, je préfère utiliser ::quand c'est possible.

std::list<int> iList;

Je déteste écrire:

for(std::list<int>::iterator i = iList.begin(); i != iList.end(); i++)
{
    //
}

J'espère qu'avec C ++ 0x j'écrirais ceci:

for(auto i = iList.begin(); i != iList.end(); i++)
{
    //
}

Si l'espace de noms est très long,

namespace dir = boost::filesystem;

dir::directory_iterator file("e:/boost");
dir::directory_iterator end;

for( ; file != end; file++)
{
    if(dir::is_directory(*file))
        std::cout << *file << std::endl;
}
AraK
la source
@AraK: namespace dir = boost :: filesystem; Je suppose que c'est un alias?
paoloricardo
@paoloricardo: Oui, c'est ce que c'est.
sbi
2
Les itérateurs doivent être incrémentés avec ++i, pas i++parce que, s'il est même défini, crée une copie temporaire inutile de l'itérateur.
Felix Dombek
2

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 verront vectorou stringnon std::, donc je pense que ce n'est pas using namespace stdmieux. C'est pourquoi je soutiens qu'il n'y aura jamais using namespace stddu 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 usingne 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::swapce qui est nécessaire (en particulier dans le code générique) pour récupérer les surcharges swap()qui ne peuvent pas être placées dans l' stdespace de noms (car nous ne sommes pas autorisés à placer des surcharges de stdfonctions dans cet espace de noms).

sbi
la source
3
Une spécialisation de std :: swap serait une spécialisation complète - vous ne pouvez pas partiellement spécialiser les modèles de fonctions. Tout programme est autorisé à spécialiser partiellement n'importe quel modèle de bibliothèque standard tant que cette spécialisation dépend d'un type défini par l'utilisateur.
CB Bailey
@Charles: Oui, vous avez raison, bien sûr, il n'y a pas de FTPS. Et je peux spécialiser les modèles à l'intérieur std, mais pas la surcharge. Désolé pour ce brainfart. Je vais corriger le message.
sbi
2
Je ne pense pas que l'intention de la using namespacedirective é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 filtrent std::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.
Lumi
@Lumi: Que vous
sbi
1
@sbi: Non, ce n'est pas objectif. Cela dépend si vous pensez que le std :: est utile ou non. Plus de désordre -> moins de clarté.
Joshua Richardson
2

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 :

#include <iostream>
#include <cmath>  // Uses ::log, which would be the log() here if it were not in a namespace, see /programming/11892976/why-is-my-log-in-the-std-namespace

// Silently overrides std::log
//double log(double d) { return 420; }

namespace uniquename {
    using namespace std;  // So we don't have to waste space on std:: when not needed.

    double log(double d) {
        return 42;
    }

    int main() {
        cout << "Our log: " << log(4.2) << endl;
        cout << "Standard log: " << std::log(4.2);
        return 0;
    }
}

// Global wrapper for our contained code.
int main() {
    return uniquename::main();
}

Production:

Our log: 42
Standard log: 1.43508
Cees Timmerman
la source
1

using namespace stdimporte le contenu de l' stdespace de noms dans celui en cours. Ainsi, l'avantage est que vous n'aurez pas à taper std::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 stdempê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 namespacedans 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.

Wookai
la source
2
using namespace std;importe le contenu de l' stdespace 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 un using namespace stdne le mettra pas comme par magie dans l' stdespace de noms.
CB Bailey
Désolé, ce n'est pas ce que je voulais dire. Merci de l'avoir signalé, je corrigerai ma réponse.
Wookai
1
Guys: merci pour les réponses. Il semble qu'en général, il est plus sûr de ne pas utiliser «using namespace std» et d'éviter de créer des ambiguïtés potentielles. Dans l'ensemble, l'utilisation de 'std :: xxx' me plaît plus que de déclarer une liste des différentes fonctions au début du fichier source car elle qualifie sans ambiguïté l'intention de chacun.
paoloricardo
1
Quote (sauf lorsque l'espace de noms est trop long). Vous pouvez utiliser l'alias d'espace de noms pour vous y aider. 'namespace Rv1 = Thor :: XML :: XPath :: Rules :: Light :: Version1;' Notez les alias et utilisez les deux respectent les règles de portée;
Martin York
0

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 stdau 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 soit using namespace std(lorsque vous utilisez une variété de classes) soit individuelleusing s (lorsque vous utilisez quelques cours souvent).

Sam Brightman
la source
0

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 et while' 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.

xtofl
la source
0

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 stdutilisent.


la source
-1

Quels sont les avantages et les inconvénients de chacun

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.

Martin Beckett
la source
Les espaces de noms ne sont pas vraiment conçus pour permettre le remplacement de noms par des fonctionnalités différentes, mais équivalentes. Ils sont conçus pour éviter les conflits de noms involontaires.
Michael Burr
Oui, donc la seule justification de la directive 'using' qui rompt ceci est de vous permettre de basculer des fonctions vers un nouvel espace de noms.
Martin Beckett
Je pense que vous trouverez énormément de programmeurs se plaignant de ce que sont les espaces de noms pénibles et voulant les jeter par la fenêtre s'il n'y avait pas de directive d'utilisation. Autant que je sache, chaque langage qui utilise des espaces de noms a quelque chose de similaire à une directive using pour les éliminer lorsque vous les voulez. Si les directives sont inutiles, pourquoi existent-elles partout?
Michael Burr
Je pense que l '"utilisation" était destinée à vous permettre de passer à des implémentations alternatives plutôt que d'économiser 3 lettres. J'aime utiliser "std :: Foo" car il sert de contrat au programmeur que j'utilise le Foo normal et qu'il n'a pas à vérifier. Je suis d'accord que je ne voudrais pas avoir à taper "com.microsoft.visual-studio.standard-library.numbers.int foo", certaines des déclarations d'itérateur dans la STL deviennent ainsi. Python fait un bon travail en vous permettant d'extraire des ensembles de fonctions décorées ou non décorées à partir de modules.
Martin Beckett
-1

Pourquoi pas par exemple

typedef std::vector<int> ints_t;
ints_t ints1;
....
ints_t ints2;

au lieu du lourd

std::vector<int> ints1;
...
std::vector<int> ints2;

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

void getHistorgram(std::vector<unsigned int>&, std::vector<unsigned int>&);

lesquels la valeur de retour?

Et plutôt

typedef std::vector<unsigned int> values_t;
typedef std::vector<unsigned int> histogram_t;
...
void getHistogram(values_t&, histogram_t&); 
ldog
la source