handling - new try catch c++




Pourquoi l'utilisation de namespace std est-elle considérée comme une mauvaise pratique? (20)

Ne l'utilisez pas globalement

Il est considéré comme "mauvais" uniquement lorsqu'il est utilisé globalement . Parce que:

  • Vous encombrez l'espace de noms que vous programmez.
  • Les lecteurs auront du mal à voir d'où provient un identifiant particulier, lorsque vous en utilisez beaucoup en using namespace xyz .
  • Ce qui est vrai pour les autres lecteurs de votre code source est encore plus vrai pour le lecteur le plus fréquent: vous-même. Revenez dans un an ou deux et jetez un coup d'œil ...
  • Si vous ne parlez que d' using namespace std vous risquez de ne pas être au courant de tout ce que vous récupérez - et lorsque vous ajoutez un autre #include ou passez à une nouvelle révision C ++, vous risquez d'obtenir des conflits de noms que vous ignoriez.

Vous pouvez l'utiliser localement

Allez-y et utilisez-le localement (presque) librement. Ceci, bien sûr, vous empêche de répéter std:: - et la répétition est également mauvaise.

Un idiome pour l'utiliser localement

En C ++ 03, il existait un idiome, le code général, pour implémenter une fonction de swap pour vos classes. Il a été suggéré que vous using namespace std réellement un using namespace std local en using namespace std - ou au moins en using std::swap :

class Thing {
    int    value_;
    Child  child_;
public:
    // ...
    friend void swap(Thing &a, Thing &b);
};
void swap(Thing &a, Thing &b) {
    using namespace std;      // make `std::swap` available
    // swap all members
    swap(a.value_, b.value_); // `std::stwap(int, int)`
    swap(a.child_, b.child_); // `swap(Child&,Child&)` or `std::swap(...)`
}

Cela fait la magie suivante:

  • Le compilateur choisira std::swap pour value_ , c’est-à-dire que void std::swap(int, int) .
  • Si vous avez un void swap(Child&, Child&) surcharge void swap(Child&, Child&) implémenté, le compilateur le choisira.
  • Si vous ne surchargez pas le compilateur, il utilisera void std::swap(Child&,Child&) et tentera de le faire en remplaçant.

Avec C ++ 11, il n’ya plus de raison d’utiliser ce modèle. L'implémentation de std::swap été modifiée pour rechercher une surcharge potentielle et la choisir.

D'autres personnes m'ont dit qu'écrire en using namespace std dans le code était une erreur et que je devrais plutôt utiliser std::cout et std::cin directement.

Pourquoi l' using namespace std considérée comme une mauvaise pratique? Est-ce inefficace ou risque-t-il de déclarer des variables ambiguës (variables qui partagent le même nom qu'une fonction dans un espace de noms std )? Cela at-il un impact sur les performances?


  1. vous devez être capable de lire du code écrit par des personnes qui ont un style différent et des opinions de meilleures pratiques que vous.

  2. Si vous utilisez uniquement cout, personne ne s'embrouille. Mais lorsque vous avez beaucoup d'espaces de noms qui volent et que vous voyez cette classe et que vous n'êtes pas tout à fait sûr de ce que ça fait, le fait d'avoir un espace de noms explicite agit comme un commentaire. Vous pouvez voir à première vue, "oh, ceci est une opération de système de fichiers" ou "c'est faire des trucs de réseau".


Ce n'est pas du tout lié à la performance. Mais considérez ceci: vous utilisez deux bibliothèques appelées Foo et Bar:

using namespace foo;
using namespace bar;

Tout fonctionne bien, vous pouvez appeler Blah() de Foo et Quux() de Bar sans problèmes. Mais un jour, vous passez à une nouvelle version de Foo 2.0, qui offre maintenant une fonction appelée Quux() . Vous avez maintenant un conflit: Foo 2.0 et Bar importent Quux() dans votre espace de noms global. Cela demandera un certain effort, en particulier si les paramètres de la fonction correspondent.

Si vous aviez utilisé foo::Blah() et bar::Quux() , alors l'introduction de foo::Quux() aurait été un non-événement.


Il ne faut pas utiliser la directive using au niveau global, en particulier dans les en-têtes. Cependant, il y a des situations où cela convient même dans un fichier d'en-tête:

template <typename FloatType> inline
FloatType compute_something(FloatType x)
{
    using namespace std; //no problem since scope is limited
    return exp(x) * (sin(x) - cos(x * 2) + sin(x * 3) - cos(x * 4));
}

C'est mieux que la qualification explicite ( std::sin , std::cos ...), car elle est plus courte et permet de travailler avec des types à virgule flottante définis par l'utilisateur (via Argument Dependent Lookup).


Je considère aussi que c'est une mauvaise pratique. Pourquoi? Un jour, j’ai pensé que la fonction d’un espace de noms consistait à diviser des éléments; je ne devais donc pas gâcher le tout en jetant tout dans un seul sac. Cependant, si j'utilise souvent 'cout' et 'cin', j'écris: using std::cout; using std::cin; using std::cout; using std::cin; dans le fichier cpp (jamais dans le fichier d'en-tête car il se propage avec #include ). Je pense que personne digne de ce nom ne nommera jamais un cout ou un film. ;)


Je conviens qu'il ne devrait pas être utilisé globalement, mais ce n'est pas si mal d'utiliser localement, comme dans un namespace . Voici un exemple tiré de "Le langage de programmation C ++" :

namespace My_lib {

    using namespace His_lib; // everything from His_lib
    using namespace Her_lib; // everything from Her_lib

    using His_lib::String; // resolve potential clash in favor of His_lib
    using Her_lib::Vector; // resolve potential clash in favor of Her_lib

}

Dans cet exemple, nous avons résolu les conflits de noms potentiels et les ambiguïtés découlant de leur composition.

Les noms explicitement déclarés ici (y compris les noms déclarés en utilisant des déclarations comme His_lib::String ) ont priorité sur les noms rendus accessibles dans une autre portée par une directive using namespace Her_lib (en using namespace Her_lib ).


Le problème de l' using namespace dans les fichiers d'en-tête de vos classes est que tout utilisateur souhaitant utiliser vos classes (en incluant vos fichiers d'en-tête) est également obligé "d'utiliser" (c'est-à-dire de tout visualiser) ces autres espaces de nom.

Cependant, vous pouvez vous sentir libre de mettre une instruction using dans vos fichiers * .cpp (privés).

Méfiez-vous que certaines personnes ne sont pas d'accord avec mon expression "ne vous sentez pas libre", car, bien qu'une déclaration using dans un fichier cpp soit meilleure que dans un en-tête (car elle ne concerne pas les personnes qui incluent votre fichier d'en-tête), elles pensent que c'est toujours le cas. pas bon (car selon le code, cela pourrait rendre la mise en œuvre de la classe plus difficile à maintenir). Ce sujet de la FAQ dit,

La directive using existe pour le code C ++ hérité et pour faciliter la transition vers les espaces de noms, mais vous ne devriez probablement pas l'utiliser régulièrement, du moins pas dans votre nouveau code C ++.

La FAQ suggère deux alternatives:

  • Une déclaration d'utilisation:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
    
  • Il suffit de taper std ::

    std::cout << "Values:";
    

Les programmeurs expérimentés utilisent ce qui résout leurs problèmes et évitent tout ce qui crée de nouveaux problèmes, et ils évitent les directives using au niveau du fichier d'en-tête pour cette raison exacte.

Les programmeurs expérimentés essaient également d'éviter la qualification complète des noms dans leurs fichiers sources. Une raison mineure à cela est qu’il n’est pas élégant d’écrire plus de code quand moins de code suffit, sauf s’il ya de bonnes raisons . Une des principales raisons est la désactivation de la recherche dépendante de l’argument (ADL).

Quelles sont ces bonnes raisons ? Parfois, les programmeurs veulent explicitement désactiver ADL, d'autres fois, ils veulent être sans ambiguïté.

Donc, ce qui suit est OK:

  1. Directives-utilisateur et déclarations-d'utilisation au niveau des fonctions dans les implémentations des fonctions
  2. Utilisation de déclarations au niveau du fichier source dans les fichiers source
  3. (Parfois) directives-utilisation au niveau du fichier source

Tout est question de gestion de la complexité. En utilisant l’espace de noms, vous obtiendrez des choses que vous ne voudrez pas, ce qui rendra probablement plus difficile le débogage (je dis peut-être). Utiliser std :: partout est plus difficile à lire (plus de texte et tout ça).

Horses for Courses - gérez votre complexité comme vous le pouvez et si vous vous en sentez capable.


Une autre raison est la surprise.

Si je vois cout << blah , au lieu de std::cout << blah

Je pense quel est ce cout ? Est-ce le cout normal? Est-ce quelque chose de spécial?


Version abrégée: n'utilisez pas global à l'aide de déclarations ou de directives dans les fichiers d'en-tête. N'hésitez pas à les utiliser dans les fichiers d'implémentation. Voici ce que Herb Sutter et Andrei Alexandrescu ont à dire à propos de cette question dans les normes de codage C ++ (le mot gras pour souligner est le mien):

Résumé

Les utilisations des espaces de noms sont destinées à votre commodité et ne doivent pas être infligées aux autres: n'écrivez jamais une déclaration using ou une directive using avant une directive #include.

Corollaire: dans les fichiers d'en-tête, n'écrivez pas au niveau de l'espace de noms à l'aide de directives ou de déclarations; au lieu de cela, explicitement les espaces de noms qualifient tous les noms. (La deuxième règle découle de la première, car les en-têtes ne peuvent jamais savoir quel autre en-tête #includes pourrait apparaître après eux.)

Discussion

En bref: vous pouvez et devez utiliser un espace de noms en utilisant des déclarations et des directives de manière libérale dans vos fichiers d’implémentation après les directives #include et sentez-vous bien. En dépit des affirmations répétées du contraire, les déclarations utilisant des déclarations et des directives ne sont pas pervers et ne vont pas à l'encontre du but des espaces de noms. Ce sont plutôt ce qui rend les espaces de noms utilisables .


Considérer

// myHeader.h
#include <sstream>
using namespace std;


// someoneElses.cpp/h
#include "myHeader.h"

class stringstream {  // uh oh
};

Notez que ceci est un exemple simple. Si vous avez des fichiers avec 20 inclusions et d'autres importations, vous aurez une tonne de dépendances à parcourir pour résoudre le problème. Le pire, c’est que vous pouvez obtenir des erreurs non liées dans d’autres modules en fonction des définitions en conflit.

Ce n'est pas horrible, mais vous éviterez des maux de tête en ne l'utilisant pas dans les fichiers d'en-tête ou dans l'espace de noms global. C'est probablement bien de le faire dans des portées très limitées, mais je n'ai jamais eu de problème à taper les 5 caractères supplémentaires pour clarifier la provenance de mes fonctions.


Un exemple où namespace std génère une erreur de compilation en raison de l'ambiguïté de count, qui est également une fonction de la bibliothèque d'algorithmes.

#include <iostream>

using namespace std;

int count = 1;
int main() {
    cout<<count<<endl;
}

"Pourquoi utiliser 'namespace std;' considéré comme une mauvaise pratique en C ++? "

Je le répète: pourquoi la saisie de 5 caractères supplémentaires est-elle considérée comme fastidieuse?

Par exemple, en écrivant un logiciel numérique, pourquoi devrais-je même envisager de polluer mon espace de noms global en coupant le "std :: vecteur" général en "vecteur" alors que "vecteur" est l'un des concepts les plus importants du domaine problématique?


C'est une mauvaise pratique, souvent appelée pollution globale par les espaces de noms. Des problèmes peuvent survenir lorsque plusieurs espaces de noms ont le même nom de fonction avec signature. Le compilateur aura alors toute ambiguïté pour décider lequel appeler et tout cela peut être évité lorsque vous spécifiez l'espace de noms avec l'appel de fonction std::cout. J'espère que cela t'aides. :)


Cela dépend de l'endroit où il se trouve. S'il s'agit d'un en-tête commun, vous diminuez la valeur de l'espace de noms en le fusionnant dans l'espace de noms global. Gardez à l'esprit, cela pourrait être une manière élégante de créer des modules globaux.


D'après mes expériences, si vous avez plusieurs bibliothèques qui utilisent say cout, mais vous pouvez utiliser le mauvais dans un but différent cout.

Par exemple, si je saisis, using namespace std;et que je ne fais que using namespace otherlib;simplement cout (plutôt que std::cout(ou 'otherlib::cout'), vous pourriez utiliser le mauvais, et obtenir des erreurs, son utilisation est beaucoup plus efficace et efficiente std::cout.


Je ne pense pas que ce soit nécessairement une mauvaise pratique dans toutes les conditions, mais vous devez faire attention lorsque vous l'utilisez. Si vous écrivez une bibliothèque, vous devriez probablement utiliser les opérateurs de résolution de portée avec l'espace de noms pour empêcher votre bibliothèque de se heurter à d'autres bibliothèques. Pour le code de niveau d'application, je ne vois rien de mal à cela.


Pour répondre à votre question, j’envisage la situation de manière pratique: beaucoup de programmeurs (pas tous) invoquent namespace std. Par conséquent, on devrait avoir l’habitude de NE PAS utiliser des choses qui empiètent ou utilisent les mêmes noms que ce qui est dans l’espace de noms std. C’est beaucoup, mais pas tellement comparé au nombre de mots cohérents et de pseudonymes possibles que l’on peut trouver à proprement parler.

Je veux dire vraiment ... dire "ne comptez pas sur sa présence", c'est simplement vous préparer à compter sur elle pour ne PAS être présente. Vous aurez constamment des problèmes pour emprunter des extraits de code et les réparer en permanence. Gardez simplement vos contenus définis et empruntés dans une portée limitée comme ils devraient être et soyez TRÈS économe avec les globals (honnêtement, les globals devraient presque toujours être un dernier recours pour les besoins de "compiler maintenant, plus tard". Vraiment, je pense que votre professeur vous a mal conseillé, car utiliser std fonctionnera à la fois pour "cout" et "std :: cout" mais NE PAS utiliser std ne fonctionnera que pour "std :: cout". Vous ne serez pas toujours assez chanceux pour écrire votre propre code.

REMARQUE: Ne vous concentrez pas trop sur les problèmes d'efficacité avant d'en apprendre un peu plus sur le fonctionnement des compilateurs. Avec un peu d'expérience en codage, vous n'avez pas besoin d'en apprendre beaucoup sur eux avant de réaliser à quel point ils sont capables de généraliser un bon code en quelque chose de simple. Aussi simple que si vous aviez tout écrit en C. Un bon code est aussi complexe qu'il le faut.


Un espace de noms est une portée nommée. Les espaces de noms sont utilisés pour regrouper les déclarations associées et pour séparer les éléments séparés. Par exemple, deux bibliothèques développées séparément peuvent utiliser le même nom pour faire référence à des éléments différents, mais un utilisateur peut toujours utiliser les deux:

namespace Mylib{
    template<class T> class Stack{ /* ... */ };
    / / ...
}
namespace Yourlib{
    class Stack{ /* ... */ };
    / / ...
}
void f(int max) {
    Mylib: :Stack<int> s1(max) ; / / use my stack
    Yourlib: :Stack s2(max) ; / / use your stack
    / / ...
}

La répétition d'un nom d'espace de noms peut être une distraction pour les lecteurs et les rédacteurs. Par conséquent, il est possible d'indiquer que les noms d'un espace de noms particulier sont disponibles sans qualification explicite. Par exemple:

void f(int max) {
    using namespace Mylib; / / make names from Mylib accessible
    Stack<int> s1(max) ; / / use my stack
    Yourlib: :Stack s2(max) ; / / use your stack
    / / ...
}

Les espaces de noms constituent un outil puissant pour la gestion de différentes bibliothèques et de différentes versions de code. En particulier, ils offrent au programmeur des alternatives sur la manière explicite de faire référence à un nom non local.

Source: Présentation du langage de programmation C ++ par Bjarne Stroustrup







c++-faq