Vraag Waarom wordt "using namespace std" beschouwd als slechte praktijk?


Mij ​​is door anderen verteld dat schrijven using namespace std in code klopt niet, en die moet ik gebruiken std::cout en std::cin rechtstreeks in plaats daarvan.

Waarom is using namespace std beschouwd als een slechte praktijk? Is het inefficiënt of loopt het het risico ambigue variabelen te declareren (variabelen die dezelfde naam hebben als een functie in std namespace)? Heeft dit invloed op de prestaties?


2061
2017-09-21 03:08


oorsprong


antwoorden:


Dit is helemaal niet gerelateerd aan prestaties. Maar overweeg dit: u gebruikt twee bibliotheken genaamd Foo en Bar:

using namespace foo;
using namespace bar;

Alles werkt goed, je kunt bellen Blah() van Foo en Quux() van Bar zonder problemen. Maar op een dag upgrade je naar een nieuwe versie van Foo 2.0, die nu een functie biedt genaamd Quux(). Nu heb je een conflict: zowel Foo 2.0 als balkimport Quux() in je globale naamruimte. Dit gaat enige moeite kosten om op te lossen, vooral als de functieparameters overeenkomen.

Als je het had gebruikt foo::Blah() en bar::Quux(), dan is de introductie van foo::Quux() zou een non-evenement geweest zijn.


1746
2017-09-21 03:13



Ik ben het met alles eens Greg schreef, maar ik zou willen toevoegen: Het kan zelfs erger worden dan Greg zei!

Bibliotheek Foo 2.0 zou een functie kunnen introduceren, Quux(), dat is een ondubbelzinnig betere overeenkomst voor sommige van uw oproepen naar Quux() dan de bar::Quux() je code heeft jarenlang gebeld. Dan is jouw code compileert nog steeds, maar het roept stilletjes de verkeerde functie en doet god-weet-wat. Dat is ongeveer net zo erg als het kan worden.

Houd er rekening mee dat de std naamruimte heeft tonnen identifiers, waarvan er vele zijn heel veel voorkomende (denk maar list, sort, string, iterator, enz.) die zeer waarschijnlijk ook in andere code zullen verschijnen.

Als u dit onwaarschijnlijk vindt: er was een vraag gesteld hier op Stack Overflow waar vrijwel precies dit gebeurde (verkeerde functie genoemd vanwege weggelaten std:: voorvoegsel) ongeveer een half jaar nadat ik dit antwoord gaf. Hier is een ander, meer recent voorbeeld van een dergelijke vraag. Dus dit is een echt probleem.


Hier is nog een datapunt: heel, vele jaren geleden vond ik het ook vervelend om alles uit de standaardbibliotheek te moeten prefixen met std::. Toen werkte ik in een project waar in het begin werd besloten dat beide using richtlijnen en verklaringen zijn verboden, behalve voor functionele scopes. Raad eens? Het kostte de meesten van ons heel weinig weken om te wennen aan het schrijven van het voorvoegsel, en na een paar weken waren de meesten van ons zelfs het erover eens dat het de code eigenlijk maakte leesbaarder. Daar is een reden voor: Of je van kortere of langere proza ​​houdt is subjectief, maar de prefixen geven objectief duidelijkheid aan de code. Niet alleen de compiler, maar ook u vindt het gemakkelijker om te zien naar welke identifier wordt verwezen.

In een decennium groeide dat project uit met enkele miljoenen regels code. Omdat deze discussies keer op keer opduiken, was ik eens nieuwsgierig hoe vaak de (toegestane) functie-scope usingdaadwerkelijk werd gebruikt in het project. Ik heb de bronnen hiervoor gegroepeerd en slechts een of twee dozijn plaatsen gevonden waar het werd gebruikt. Dit geeft voor mij aan dat, eenmaal geprobeerd, ontwikkelaars het niet vinden std:: pijnlijk genoeg om zelfs eens per 100 kLoC richtlijnen toe te passen, zelfs als het toegestaan ​​was om gebruikt te worden.


Kort gezegd: het expliciet voorvoegen van alles doet geen kwaad, neemt heel weinig gewenning en heeft objectieve voordelen. In het bijzonder maakt het de code gemakkelijker te interpreteren door de compiler en door menselijke lezers - en dat zou waarschijnlijk het hoofddoel moeten zijn bij het schrijven van code.


1147
2017-09-21 09:26



Ik denk dat het slecht is om het in de header-bestanden van je klassen te plaatsen: omdat je dan iedereen zou dwingen die jouw klassen wil gebruiken (door je header-bestanden op te nemen) om ook te 'gebruiken' (dwz alles te zien) die andere namespaces .

U kunt echter gerust een gebruikstatement in uw (persoonlijke) * .cpp-bestanden plaatsen.


Pas op dat sommige mensen het niet eens zijn met mijn uitspraak "vrij voelen" op deze manier - omdat een gebruikende verklaring in een cpp-bestand dat wel is beter dan in een header (omdat het geen invloed heeft op mensen die je header-bestand opnemen), denken ze dat het dat nog steeds niet is goed (omdat het afhankelijk van de code de implementatie van de klasse moeilijker zou maken om te onderhouden). Dit FAQ-onderwerp zegt,

De gebruik-instructie bestaat voor oudere C ++-code en om de overgang naar naamruimten te vergemakkelijken, maar je zou het waarschijnlijk niet op een regelmatige basis moeten gebruiken, althans niet in je nieuwe C ++ -code.

Het suggereert twee alternatieven:

  • Een gebruikende verklaring:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
    
  • Ga eroverheen en typ gewoon std:

    std::cout << "Values:";
    

308
2017-09-21 03:22



Ik kwam onlangs een klacht tegen over Visual Studio 2010. Het bleek dat vrijwel alle bronbestanden deze twee lijnen hadden:

using namespace std;
using namespace boost;

Veel van boost functies gaan in de C ++ 0x-standaard, en Visual Studio 2010 heeft veel C ++ 0x-functies, dus deze programma's waren plotseling niet aan het compileren.

Daarom vermijden using namespace X; is een vorm van future-proofing, een manier om ervoor te zorgen dat een verandering in de gebruikte bibliotheken en / of header-bestanden geen programma zal doorbreken.


197
2017-10-28 17:37



Korte versie: gebruik geen globale verklaringen of richtlijnen in header-bestanden. Gebruik deze gerust in implementatiebestanden. Dit is wat Herb Sutter en Andrei Alexandrescu hierover te zeggen hebben C ++ coderingsnormen (veterschillend voor de nadruk is van mij):

Overzicht

Het gebruik van de naamruimtes is voor uw gemak, niet voor u om anderen schade toe te brengen: Schrijf nooit een gebruikende verklaring of een gebruikende richtlijn vóór een richtlijn #include.

Corollary: schrijf in header-bestanden geen namespace-level met behulp van richtlijnen of met behulp van declaraties; in plaats daarvan expliciet namespace-kwalificeer alle namen. (De tweede regel volgt op de eerste, omdat kopteksten nooit kunnen weten welke andere koptekst #opnamen erna kunnen verschijnen.)

Discussie

In het kort: U kunt en moet de naamruimte gebruiken met behulp van verklaringen en richtlijnen royaal in uw implementatiebestanden na #include richtlijnen en er goed over voelen. Ondanks herhaalde beweringen van het tegendeel, is namespace met verklaringen en richtlijnen niet slecht en ze verslaan het doel van namespaces niet. Integendeel, ze maken namespaces bruikbaar.


159
2017-11-03 20:00



Men zou het gebruik van richtlijnen op wereldschaal niet moeten gebruiken, vooral in headers. Er zijn echter situaties waarin dit zelfs in een headerbestand gepast is:

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));
}

Dit is beter dan expliciete kwalificatie (std::sin, std::cos...) omdat het korter is en de mogelijkheid heeft om te werken met door de gebruiker gedefinieerde drijvende-kommatypes (via Betrokken zoekactie op basis van argumenten).


103
2017-09-21 15:47



Gebruik het niet wereldwijd

Het wordt alleen als "slecht" beschouwd als wanneer wereldwijd gebruikt. Omdat:

  • Je hebt een rommel in de naamruimte waarin je programmeert.
  • Lezers zullen moeite hebben om te zien waar een bepaalde identifier vandaan komt, wanneer je er veel gebruikt using namespace xyz.
  • Waar is waar voor anders lezers van uw broncode geldt nog meer voor de meest frequente lezer ervan: uzelf. Kom over een jaar of twee terug en kijk eens ...
  • Als je alleen maar over praat using namespace std je bent je misschien niet bewust van alle dingen die je pakt - en wanneer je er nog een toevoegt #include of ga naar een nieuwe C ++ -revisie, zodat u mogelijk naamconflicten krijgt waarvan u zich niet bewust was.

Je kunt het lokaal gebruiken

Ga je gang en gebruik het lokaal (bijna) vrijelijk. Dit voorkomt natuurlijk dat je herhaling van std:: - en herhaling is ook slecht.

Een idioom om het lokaal te gebruiken

In C ++ 03 was er een idioom - boilerplate code - voor het implementeren van a swap functie voor uw lessen. Er is gesuggereerd dat u daadwerkelijk een lokaal gebruikt using namespace std -- of ten minste 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(...)`
}

Dit doet de volgende magie:

  • De compiler kiest de std::swap voor value_, i.e. void std::swap(int, int).
  • Als u overbelasting heeft void swap(Child&, Child&) geïmplementeerd de compiler zal het kiezen.
  • Als je dat doet niet heb die overbelasting die de compiler zal gebruiken void std::swap(Child&,Child&) en probeer deze het beste te verwisselen.

Met C ++ 11 is er geen reden meer om dit patroon te gebruiken. De implementatie van std::swap is gewijzigd om een ​​potentiële overbelasting te vinden en deze te kiezen.


80
2018-01-18 09:34



Als je de juiste header-bestanden importeert, heb je ineens namen als hex, left, plus of count in uw mondiale bereik. Dit kan verrassend zijn als je je daar niet bewust van bent std:: bevat deze namen. Als u ook probeert deze namen lokaal te gebruiken, kan dit tot nogal wat verwarring leiden.

Als alle standaarddingen zich in een eigen naamruimte bevinden, hoeft u zich geen zorgen te maken over naambotsingen met uw code of andere bibliotheken.


71
2017-09-21 03:23