Waarom wordt het gebruik van naamruimte std; beschouwd als een slechte gewoonte?

Anderen hebben mij verteld dat het schrijven van using namespace std; in code verkeerd is, en dat ik std::cout en std::cin rechtstreeks in plaats daarvan.

Waarom wordt using namespace std; als een slechte gewoonte beschouwd? Is het inefficiënt of loopt het het risico dubbelzinnige variabelen te declareren (variabelen die dezelfde naam delen als een functie in de std naamruimte)? Heeft het invloed op de prestaties?


Antwoord 1, autoriteit 100%

Dit heeft helemaal niets met prestaties te maken. Maar denk hier eens over na: je gebruikt twee bibliotheken genaamd Foo en Bar:

using namespace foo;
using namespace bar;

Alles werkt prima, en je kunt zonder problemen Blah() vanuit Foo en Quux() vanuit Bar aanroepen. Maar op een dag upgrade je naar een nieuwe versie van Foo 2.0, die nu een functie biedt met de naam Quux(). Nu heb je een conflict: zowel Foo 2.0 als Bar importeren Quux() in je globale naamruimte. Het zal wat moeite kosten om dit op te lossen, vooral als de functieparameters overeenkomen.

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


Antwoord 2, autoriteit 60%

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

Bibliotheek Foo 2.0 zou een functie kunnen introduceren, Quux(), die ondubbelzinnig beter overeenkomt met sommige van uw aanroepen naar Quux() dan de bar::Quux() uw code heeft jarenlang gebeld. Dan compileert je code nog steeds, maar het roept stilletjes de verkeerde functie aan en doet god-weet-wat. Dat is ongeveer zo erg als maar kan.

Houd er rekening mee dat de naamruimte std heel veel identifiers heeft, waarvan vele zeer veelvoorkomende zijn (denk aan list, sort, string, iterator, etc.) die zeer waarschijnlijk ook in andere code voorkomen.

Als u dit onwaarschijnlijk acht: er werd een vraag gesteld hier op Stack Overflow waar dit vrijwel precies gebeurde (verkeerd functie aangeroepen vanwege weggelaten std:: prefix) ongeveer een half jaar nadat ik dit antwoord gaf. Hier is een ander, recenter voorbeeld van zo’n vraag.
Dit is dus een echt probleem.


Hier is nog een gegevenspunt: vele, vele jaren geleden vond ik het ook vervelend om alles uit de standaardbibliotheek vooraf te moeten zetten met std::. Daarna werkte ik in een project waar bij de start werd besloten dat zowel using richtlijnen als declaraties verboden zijn, behalve voor functiebereiken. Raad eens? Het kostte de meesten van ons maar een paar weken om te wennen aan het schrijven van het voorvoegsel, en na een paar weken waren de meesten het er zelfs over eens dat het de code in feite leesbaarder maakte. Daar is een reden voor: Of je van korter of langer proza ​​houdt, is subjectief, maar de voorvoegsels geven objectief duidelijkheid aan de code. Niet alleen de compiler, maar ook jij, vind het gemakkelijker om te zien naar welke identifier wordt verwezen.

In tien jaar tijd groeide dat project uit tot enkele miljoenen regels code. Aangezien deze discussies steeds weer terugkomen, was ik eens benieuwd hoe vaak de (toegestane) functie-scope using daadwerkelijk in het project werd gebruikt. Ik heb de bronnen ervoor gevonden en vond slechts een of twee dozijn plaatsen waar het werd gebruikt. Voor mij geeft dit aan dat, eenmaal geprobeerd, ontwikkelaars std:: niet pijnlijk genoeg vinden om richtlijnen te gebruiken, zelfs niet om de 100 kLoC, zelfs niet waar het gebruikt mocht worden.


Kortom: het expliciet voorvoegen van alles kan geen kwaad, is even wennen 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.


Antwoord 3, autoriteit 19%

Het probleem met het plaatsen van using namespace in de header-bestanden van uw klassen is dat het iedereen die uw klassen wil gebruiken (door uw header-bestanden op te nemen) dwingt om ook te ‘gebruiken’ (dwz te zien alles in) die andere naamruimten.

U kunt echter gerust een gebruiksverklaring in uw (privé) *.cpp-bestanden plaatsen.


Pas op dat sommige mensen het niet eens zijn met mijn uitspraak “voel je vrij” op deze manier — want hoewel een using-instructie in een cpp-bestand beter is dan in een koptekst (omdat het heeft geen invloed op mensen die je headerbestand opnemen), ze denken dat het nog steeds niet goed is (omdat het, afhankelijk van de code, de implementatie van de klasse moeilijker te onderhouden zou kunnen maken). Dit C++ Super-FAQ-item zegt:

De gebruiksrichtlijn bestaat voor verouderde C++-code en om de overgang naar naamruimten te vergemakkelijken, maar u moet deze waarschijnlijk niet regelmatig gebruiken, althans niet in uw nieuwe C++-code.

De FAQ stelt twee alternatieven voor:

  • Een gebruiksverklaring:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
    
  • Typ gewoon std::

    std::cout << "Values:";
    

Antwoord 4, autoriteit 10%

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

using namespace std;
using namespace boost;

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

Daarom is het vermijden van using namespace X; een vorm van toekomstbestendig maken, een manier om ervoor te zorgen dat een wijziging in de gebruikte bibliotheken en/of headerbestanden een programma niet kapot maakt.


Antwoord 5, autoriteit 9%

Korte versie: gebruik geen globale using declaraties of richtlijnen in header-bestanden. Voel je vrij om ze te gebruiken in implementatiebestanden. Dit is wat Herb Sutter en Andrei Alexandrescu te zeggen hebben over dit probleem in C++-coderingsnormen (vetgedrukt voor nadruk is van mij):

Samenvatting

Het gebruik van naamruimten is voor uw gemak, niet om anderen op te leggen: schrijf nooit een gebruiksdeclaratie of een gebruiksinstructie vóór een #include-instructie.

Gevolg: schrijf in header-bestanden geen naamruimte-niveau met behulp van richtlijnen of met behulp van declaraties; in plaats daarvan, expliciet naamruimte-kwalificeren alle namen. (De tweede regel volgt op de eerste, omdat kopteksten nooit kunnen weten welke andere koptekst #includes erna zou kunnen verschijnen.)

Discussie

Kortom: u kunt en moet naamruimte vrij gebruiken door verklaringen en richtlijnen te gebruiken in uw implementatiebestanden na #include-richtlijnen en u voelt zich daar goed bij. Ondanks herhaalde beweringen van het tegendeel, zijn naamruimten die verklaringen en richtlijnen gebruiken niet slecht en ze verslaan het doel van naamruimten niet. In plaats daarvan maken ze naamruimten bruikbaar.


Antwoord 6, autoriteit 5%

Men moet de using-instructie niet gebruiken in de globale scope, vooral niet in headers. Er zijn echter situaties waarin het 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 met gebruikers te werken gedefinieerde drijvende-kommatypen (via argumentafhankelijke opzoeking (ADL)).


Antwoord 7, autoriteit 4%

Gebruik het niet wereldwijd

Het wordt alleen als ‘slecht’ beschouwd als het wereldwijd wordt gebruikt. Omdat:

  • Je maakt de naamruimte waarin je programmeert onoverzichtelijk.
  • Lezers zullen moeite hebben om te zien waar een bepaalde identifier vandaan komt, wanneer je veel using namespace xyz.
  • Wat waar is voor andere lezers van uw broncode, geldt nog meer voor de meest frequente lezer ervan: uzelf. Kom over een jaar of twee terug en neem een ​​kijkje…
  • Als je alleen praat over using namespace std, ben je je misschien niet bewust van alle dingen die je pakt — en wanneer je nog een #include toevoegt of naar een nieuwe C++ revisie krijgt u mogelijk naamconflicten waarvan u zich niet bewust was.

Je mag het lokaal gebruiken

Ga je gang en gebruik het lokaal (bijna) vrij. Dit voorkomt natuurlijk dat u std:: herhaalt — 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 een swap-functie voor je klassen. Er werd gesuggereerd dat u daadwerkelijk een lokale using namespace std — of in ieder geval 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_, dwz void std::swap(int, int).
  • Als je een overload void swap(Child&, Child&) hebt geïmplementeerd, zal de compiler deze kiezen.
  • Als je niet die overbelasting hebt, zal de compiler void std::swap(Child&,Child&) gebruiken en zijn best doen om deze om te wisselen.
  • >

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


Antwoord 8, autoriteit 3%

Als je de juiste header-bestanden importeert, heb je opeens namen als hex, left, plus of count in uw globale bereik. Dit kan verrassend zijn als je niet weet dat std:: deze namen bevat. Als je deze namen ook lokaal probeert te gebruiken, kan dat tot nogal wat verwarring leiden.

Als alle standaarddingen in hun eigen naamruimte staan, hoeft u zich geen zorgen te maken over naamconflicten met uw code of andere bibliotheken.


Antwoord 9, autoriteit 2%

Een andere reden is verrassing.

Als ik cout << blah, in plaats van std::cout << blah Ik denk: wat is dit cout? Is het de normale cout? Is het iets speciaals?


Antwoord 10, autoriteit 2%

Ervaren programmeurs gebruiken alles wat hun problemen oplost en vermijden alles wat nieuwe problemen veroorzaakt, en ze vermijden om deze reden gebruiksrichtlijnen op header-bestandsniveau.

Ervaren programmeurs proberen ook volledige kwalificatie van namen in hun bronbestanden te vermijden. Een kleine reden hiervoor is dat het niet elegant is om meer code te schrijven als minder code voldoende is tenzij daar goede redenen voor zijn. Een belangrijke reden hiervoor is het uitschakelen van argument-dependent lookup (ADL).

Wat zijn deze goede redenen? Soms willen programmeurs ADL expliciet uitschakelen, soms willen ze het ondubbelzinnig maken.

Dus het volgende is in orde:

  1. Gebruiksrichtlijnen op functieniveau en gebruiksdeclaraties in implementaties van functies
  2. Gebruiksdeclaraties op bronbestandsniveau in bronbestanden
  3. (Soms) gebruiksrichtlijnen op bronbestandsniveau

Antwoord 11, autoriteit 2%

Ik ben het ermee eens dat het niet wereldwijd mag worden gebruikt, maar het is niet zo slecht om lokaal te gebruiken, zoals in een namespace. Hier is een voorbeeld uit “De programmeertaal 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
}

In dit voorbeeld hebben we mogelijke naamconflicten en dubbelzinnigheden opgelost die voortkomen uit hun samenstelling.

Namen die daar expliciet zijn gedeclareerd (inclusief namen die zijn gedeclareerd door gebruiksdeclaraties zoals His_lib::String) hebben voorrang op namen die in een ander bereik toegankelijk zijn gemaakt door een gebruiksrichtlijn (using namespace Her_lib).


Antwoord 12

Ik vind het ook een slechte gewoonte. Waarom? Op een dag dacht ik dat de functie van een naamruimte is om dingen te verdelen, dus ik moet het niet verpesten door alles in één globale tas te gooien.

Als ik echter vaak ‘cout’ en ‘cin’ gebruik, schrijf ik: using std::cout; using std::cin; in het .cpp-bestand (nooit in het headerbestand zoals het zich voortplant met #include). Ik denk dat niemand met gezond verstand ooit een stream cout of cin zal noemen. 😉


Antwoord 13

Het is fijn om code te zien en te weten wat deze doet. Als ik std::cout zie, weet ik dat dit de cout-stroom is van de std-bibliotheek. Als ik cout zie, dan weet ik het niet. Het zou de cout-stroom van de std-bibliotheek kunnen zijn. Of er kan een int cout = 0; tien regels hoger zijn in dezelfde functie. Of een static variabele met de naam cout in dat bestand. Het kan van alles zijn.

Neem nu een codebasis van een miljoen regels, wat niet bijzonder groot is, en je bent op zoek naar een bug, wat betekent dat je weet dat er één regel in deze miljoen regels zit die niet doet wat het zou moeten doen doen. cout << 1; kan een static int met de naam cout lezen, deze een bit naar links verschuiven en het resultaat weggooien. Op zoek naar een bug, dat zou ik moeten nakijken. Kun je zien hoe ik het liefst std::cout zie?

Het is een van deze dingen die een heel goed idee lijken als je een leraar bent en nooit code hoeft te schrijven en te onderhouden voor je brood. Ik hou ervan om code te zien waar (1) ik weet wat het doet; en, (2) ik ben ervan overtuigd dat de persoon die het schrijft wist wat het doet.


Antwoord 14

Het draait allemaal om het managen van complexiteit. Het gebruik van de naamruimte zal dingen binnenhalen die je niet wilt, en dus mogelijk moeilijker maken om te debuggen (ik zeg mogelijk). Het gebruik van std:: overal is moeilijker te lezen (meer tekst en zo).

Paarden voor cursussen – beheer uw complexiteit hoe u het beste kunt en voelt.


Antwoord 15

Overweeg

// myHeader.h
#include <sstream>
using namespace std;
// someoneElses.cpp/h
#include "myHeader.h"
class stringstream {  // Uh oh
};

Merk op dat dit een eenvoudig voorbeeld is. Als je bestanden hebt met 20 include en andere importen, zul je een heleboel afhankelijkheden moeten doorlopen om het probleem te achterhalen. Het ergste is dat je niet-gerelateerde fouten kunt krijgen in andere modules, afhankelijk van de definities die conflicteren.

Het is niet verschrikkelijk, maar je bespaart jezelf kopzorgen door het niet te gebruiken in header-bestanden of de globale naamruimte. Het is waarschijnlijk goed om het in een zeer beperkt bereik te doen, maar ik heb nooit een probleem gehad met het typen van de extra vijf tekens om te verduidelijken waar mijn functies vandaan komen.


Antwoord 16

Een concreet voorbeeld om de zorg te verduidelijken. Stel je voor dat je een situatie hebt waarin je twee bibliotheken hebt, foo en bar, elk met hun eigen naamruimte:

namespace foo {
    void a(float) { /* Does something */ }
}
namespace bar {
    ...
}

Stel nu dat u foo en bar als volgt samen in uw eigen programma gebruikt:

using namespace foo;
using namespace bar;
void main() {
    a(42);
}

Op dit moment is alles in orde. Wanneer u uw programma uitvoert, ‘doet het iets’. Maar later update je bar en laten we zeggen dat het is veranderd in:

namespace bar {
    void a(float) { /* Does something completely different */ }
}

Op dit punt krijg je een compilerfout:

using namespace foo;
using namespace bar;
void main() {
    a(42);  // error: call to 'a' is ambiguous, should be foo::a(42)
}

Je zult dus wat onderhoud moeten plegen om te verduidelijken dat ‘a’ foo::a betekende. Dat is onwenselijk, maar gelukkig is het vrij eenvoudig (voeg gewoon foo:: toe vóór alle aanroepen van a die de compiler als dubbelzinnig markeert).

Maar stel je een alternatief scenario voor waarbij de balk in plaats daarvan veranderde om er zo uit te zien:

namespace bar {
    void a(int) { /* Does something completely different */ }
}

Op dit punt wordt uw aanroep naar a(42) plotseling gekoppeld aan bar::a in plaats van foo::a en in plaats van door ‘iets’ te doen, doet het ‘iets heel anders’. Geen compilerwaarschuwing of iets dergelijks. Je programma begint gewoon stilletjes iets heel anders te doen dan voorheen.

Als je een naamruimte gebruikt, riskeer je een scenario als dit, en daarom voelen mensen zich ongemakkelijk bij het gebruik van naamruimten. Hoe meer dingen in een naamruimte, hoe groter het risico op conflicten, dus mensen kunnen zich nog ongemakkelijker voelen bij het gebruik van naamruimte std (vanwege het aantal dingen in die naamruimte) dan andere naamruimten.

Uiteindelijk is dit een afweging tussen beschrijfbaarheid versus betrouwbaarheid/onderhoudbaarheid. Leesbaarheid kan ook een rol spelen, maar ik kan argumenten zien om dat beide kanten op te gaan. Normaal gesproken zou ik zeggen dat betrouwbaarheid en onderhoudbaarheid belangrijker zijn, maar in dit geval betaalt u constant de beschrijfbaarheidskosten voor een vrij zeldzame impact op betrouwbaarheid/onderhoud. De ‘beste’ afweging is bepalend voor uw project en uw prioriteiten.


Antwoord 17

Het gebruik van veel naamruimten tegelijk is natuurlijk een recept voor rampen, maar het gebruik van JUST namespace std en alleen namespace std is naar mijn mening niet zo’n probleem omdat herdefinitie alleen kan plaatsvinden door uw eigen code…

Beschouw ze dus gewoon als functies als gereserveerde namen zoals “int” of “class” en dat is het dan.

Mensen zouden moeten ophouden er zo anaal over te doen. Je leraar had al die tijd gelijk. Gebruik gewoon EEN naamruimte; dat is het hele punt van het gebruik van naamruimten in de eerste plaats. Het is niet de bedoeling dat u er meer dan één tegelijk gebruikt. Tenzij het je eigen is. Dus nogmaals, herdefinitie zal niet gebeuren.


Antwoord 18

  1. Je moet code kunnen lezen die is geschreven door mensen die een andere stijl en best practices hebben dan jij.

  2. Als je alleen cout gebruikt, raakt niemand in de war. Maar als je veel naamruimten hebt die rondvliegen en je ziet deze klasse en je weet niet precies wat het doet, dan werkt het expliciet hebben van de naamruimte als een soort opmerking. Je kunt op het eerste gezicht zien, “oh, dit is een bestandssysteembewerking” of “dat doet netwerkdingen”.


Antwoord 19

Ik ben het eens met de anderen hier, maar ik wil graag de zorgen met betrekking tot de leesbaarheid wegnemen – je kunt dat allemaal vermijden door gewoon typedefs bovenaan je bestand, functie of klassedeclaratie te gebruiken.

Ik gebruik het meestal in mijn klassendeclaratie omdat methoden in een klasse de neiging hebben om met vergelijkbare gegevenstypen (de leden) om te gaan en een typedef is een mogelijkheid om een ​​naam toe te wijzen die betekenisvol is in de context van de klasse. Dit bevordert de leesbaarheid in de definities van de klassenmethoden.

// Header
class File
{
   typedef std::vector<std::string> Lines;
   Lines ReadLines();
}

en in de uitvoering:

// .cpp
Lines File::ReadLines()
{
    Lines lines;
    // Get them...
    return lines;
}

in tegenstelling tot:

// .cpp
vector<string> File::ReadLines()
{
    vector<string> lines;
    // Get them...
    return lines;
}

of:

// .cpp
std::vector<std::string> File::ReadLines()
{
    std::vector<std::string> lines;
    // Get them...
    return lines;
}

Antwoord 20

Een naamruimte is een benoemd bereik. Naamruimten worden gebruikt om gerelateerde declaraties te groeperen en gescheiden te houden
artikelen gescheiden. Twee afzonderlijk ontwikkelde bibliotheken kunnen bijvoorbeeld dezelfde naam gebruiken om naar verschillende
items, maar een gebruiker kan nog steeds beide gebruiken:

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

Het herhalen van een naamruimtenaam kan zowel lezers als schrijvers afleiden. Daardoor is het mogelijk
om aan te geven dat namen uit een bepaalde naamruimte beschikbaar zijn zonder expliciete kwalificatie. Bijvoorbeeld:

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

Naamruimten bieden een krachtig hulpmiddel voor het beheer van verschillende bibliotheken en verschillende versies van code. In het bijzonder bieden ze de programmeur alternatieven voor hoe expliciet een verwijzing naar een niet-lokale naam kan worden gemaakt.

Bron: Een overzicht van de programmeertaal C++
door Bjarne Stroustrup


Antwoord 21

Een voorbeeld waarbij using namespace std een compilatiefout genereert vanwege de dubbelzinnigheid van count, wat ook een functie is in de algoritmebibliotheek.

#include <iostream>
#include <algorithm>
using namespace std;
int count = 1;
int main() {
    cout << count << endl;
}

Antwoord 22

Het maakt uw software of projectprestaties niet slechter. Het opnemen van de naamruimte aan het begin van uw broncode is niet slecht. Het opnemen van de instructie using namespace std hangt af van uw behoeften en de manier waarop u de software of het project ontwikkelt.

De using namespace std bevat de C++ standaardfuncties en variabelen. Deze naamruimte is handig wanneer u vaak de C++ standaardfuncties zou gebruiken.

Zoals vermeld op deze pagina:

De instructie die namespace std gebruikt, wordt over het algemeen als slecht beschouwd
oefening. Het alternatief voor deze verklaring is het specificeren van de
naamruimte waartoe de id behoort met behulp van de scope-operator (::)
elke keer dat we een type declareren.

En zie deze mening:

Er is geen probleem om “namespace std gebruiken” in uw bronbestand te gebruiken
wanneer u intensief gebruik maakt van de naamruimte en zeker weet dat
niets zal botsen.

Sommige mensen hadden gezegd dat het een slechte gewoonte is om using namespace std in je bronbestanden op te nemen, omdat je vanuit die naamruimte alle functies en variabelen aanroept. Als u een nieuwe functie wilt definiëren met dezelfde naam als een andere functie in de using namespace std, dan zou u de functie overbelasten en dit zou problemen kunnen veroorzaken bij het compileren of uitvoeren. Het zal niet compileren of uitvoeren zoals je verwacht.

Zoals vermeld op deze pagina:

Hoewel de instructie ons behoedt voor het typen van std:: when
we toegang willen tot een klasse of type gedefinieerd in de std namespace, it
importeert het geheel van de std-naamruimte in de huidige naamruimte
van het programma. Laten we een paar voorbeelden nemen om te begrijpen waarom dit
misschien niet zo’n goede zaak

Nu, in een later ontwikkelingsstadium, willen we een andere versie gebruiken van
cout die op maat is geïmplementeerd in een bibliotheek genaamd foo (voor
voorbeeld)

Let op hoe er een dubbelzinnigheid is, naar welke bibliotheek verwijst cout?
De compiler kan dit detecteren en het programma niet compileren. in het ergste geval
In dit geval kan het programma nog steeds compileren, maar de verkeerde functie aanroepen, aangezien
we hebben nooit gespecificeerd tot welke naamruimte de identifier behoorde.


Antwoord 23

Het is per geval. We willen de “total cost of ownership” van de software gedurende de levensduur minimaliseren. Het vermelden van “namespace std gebruiken” brengt kosten met zich mee, maar het niet gebruiken ervan heeft ook kosten voor de leesbaarheid.

Mensen wijzen er terecht op dat wanneer je het gebruikt, wanneer de standaardbibliotheek nieuwe symbolen en definities introduceert, je code niet meer wordt gecompileerd en dat je mogelijk gedwongen wordt om variabelen te hernoemen. En toch is dit waarschijnlijk goed voor de lange termijn, aangezien toekomstige beheerders tijdelijk in de war of afgeleid zullen zijn als je een zoekwoord voor een verrassend doel gebruikt.

U wilt niet willen een sjabloon genaamd vector hebben, wat niet de vector is die bij alle anderen bekend is. En het aantal nieuwe definities dat op deze manier in de C++-bibliotheek is geïntroduceerd, is klein genoeg dat het misschien gewoon niet naar voren komt. Er zijn kosten verbonden aan het uitvoeren van dit soort wijzigingen, maar de kosten zijn niet hoog en worden gecompenseerd door de duidelijkheid die wordt verkregen door geen std symboolnamen voor andere doeleinden te gebruiken.

Gezien het aantal klassen, variabelen en functies, kan het vermelden van std:: op elke code je code met 50% vertroebelen en het moeilijker maken om je hoofd erbij te houden. Een algoritme of stap in een methode die op één scherm vol code kan worden opgenomen, vereist nu heen en weer scrollen om te volgen. Dit zijn reële kosten. Het is misschien geen hoge prijs, maar mensen die ontkennen dat het bestaat, zijn onervaren, dogmatisch of hebben het gewoon bij het verkeerde eind.

Ik bied de volgende regels aan:

  1. std is anders dan alle andere bibliotheken. Het is de enige bibliotheek die iedereen eigenlijk moet kennen, en naar mijn mening kan het het beste worden beschouwd als onderdeel van de taal. Over het algemeen is er een uitstekende reden om using namespace std te gebruiken, zelfs als er geen andere bibliotheken zijn.

  2. Dwing de beslissing nooit af aan de auteur van een compilatie-eenheid (een .cpp-bestand) door deze using in een koptekst te plaatsen. Altijd stel de beslissing uit aan de auteur van de compilatie-eenheid. Zelfs in een project dat heeft besloten om overal using namespace std te gebruiken, kunnen een paar modules boeten die het beste als uitzondering op die regel kunnen worden behandeld.

  3. Ook al kun je met de naamruimtefunctie veel modules hebben met symbolen die hetzelfde zijn gedefinieerd, het zal verwarrend zijn om dit te doen. Houd de namen zoveel mogelijk anders. Zelfs als je de naamruimtefunctie niet gebruikt, als je een klasse hebt met de naam foo en std een klasse met de naam foo introduceert, is het waarschijnlijk beter op lange termijn om je klas toch te hernoemen.

  4. Een alternatief voor het gebruik van naamruimten is om naamruimtesymbolen handmatig te gebruiken door ze vooraf te laten gaan. Ik heb twee bibliotheken die ik al tientallen jaren gebruik, beide beginnend als C-bibliotheken, eigenlijk, waar elk symbool wordt voorafgegaan door “AK” of “SCWin”. Over het algemeen is dit hetzelfde als het vermijden van de “gebruikende” constructie, maar je schrijft de dubbele dubbele punt niet. AK::foo() is in plaats daarvan AKFoo(). Het maakt code 5-10% dichter en minder uitgebreid, en het enige nadeel is dat je grote problemen krijgt als je twee van zulke bibliotheken moet gebruiken die dezelfde prefix hebben. Merk op dat de X Window-bibliotheken in dit opzicht uitstekend zijn, behalve dat ze zijn vergeten dit te doen met een paar #defines: TRUE en FALSE hadden XTRUE en XFALSE moeten zijn, en dit zorgde voor een naamruimte-clash met Sybase of Oracle die ook TRUE en FALSE gebruikten met verschillende waarden! (ASCII 0 en 1 in het geval van de database!) Een speciaal voordeel hiervan is dat het naadloos van toepassing is op preprocessor-definities, terwijl het C++ using/namespace-systeem dat niet doet. ik behandel ze niet. Een mooi voordeel hiervan is dat het een organische helling geeft van onderdeel van een project naar uiteindelijk bibliotheek. In een grote applicatie van mij hebben alle vensterklassen het voorvoegsel Win, alle signaalverwerkingsmodules Mod, enzovoort. Er is weinig kans dat deze worden hergebruikt, dus het heeft geen praktisch voordeel om van elke groep een bibliotheek te maken, maar het wordt binnen een paar seconden duidelijk hoe het project in subprojecten opsplitst.


Antwoord 24

Ik ben het met anderen eens het is vragen om naamconflicten, dubbelzinnigheden en dan is het een feit dat het minder expliciet is. Hoewel ik het gebruik van using kan zien, is mijn persoonlijke voorkeur om het te beperken. Ik zou ook sterk overwegen wat sommige anderen opmerkten:

Als u een functienaam wilt vinden die misschien een vrij veel voorkomende naam is, maar u wilt deze alleen vinden in de std naamruimte (of omgekeerd u wilt alle aanroepen wijzigen die niet in naamruimte std, naamruimte X, …), hoe stel je dan voor om dit te doen?

Je zou er een programma voor kunnen schrijven, maar zou het niet beter zijn om tijd aan je project zelf te besteden in plaats van een programma te schrijven om je project te onderhouden?

Persoonlijk vind ik het voorvoegsel std:: niet erg. Ik hou meer van het uiterlijk dan het niet hebben. Ik weet niet of dat komt omdat het expliciet is en tegen me zegt “dit is niet mijn code… ik gebruik de standaardbibliotheek” of dat het iets anders is, maar ik vind het er mooier uitzien. Dit is misschien vreemd gezien het feit dat ik pas onlangs met C++ ben begonnen (gebruik en doe nog steeds C en andere talen veel langer en C is mijn favoriete taal aller tijden, net boven assembly).

Er is nog iets anders, hoewel het enigszins gerelateerd is aan het bovenstaande en wat anderen aangeven. Hoewel dit misschien een slechte gewoonte is, reserveer ik soms std::name voor de standaardbibliotheekversie en naam voor programmaspecifieke implementatie. Ja, inderdaad, dit kan je bijten en hard bijten, maar het komt er allemaal op neer dat ik dit project helemaal opnieuw ben begonnen, en ik ben de enige programmeur ervoor. Voorbeeld: ik overbelast std::string en noem het string. Ik heb nuttige aanvullingen. Ik deed het gedeeltelijk vanwege mijn neiging tot C en Unix (+ Linux) naar namen in kleine letters.

Daarnaast kunt u naamruimte-aliassen hebben. Hier is een voorbeeld van waar het nuttig is waar misschien niet naar is verwezen. Ik gebruik de C++11-standaard en specifiek met libstdc++. Wel, het heeft geen volledige std::regex ondersteuning. Natuurlijk, het compileert, maar het genereert een uitzondering in de trant van een fout aan de kant van de programmeur. Maar het is een gebrek aan implementatie.

Dus hier is hoe ik het heb opgelost. Installeer de regex van Boost en koppel deze. Vervolgens doe ik het volgende zodat wanneer libstdc++ het volledig heeft geïmplementeerd, ik alleen dit blok hoef te verwijderen en de code hetzelfde blijft:

namespace std
{
    using boost::regex;
    using boost::regex_error;
    using boost::regex_replace;
    using boost::regex_search;
    using boost::regex_match;
    using boost::smatch;
    namespace regex_constants = boost::regex_constants;
}

Ik zal er niet over twisten of dat een slecht idee is of niet. Ik zal echter beweren dat het het schoon houdt voor mijn project en het tegelijkertijd specifiek maakt: waar, ik moet Boost gebruiken, maar ik gebruik het zoals de libstdc++ zal het uiteindelijk hebben. Ja, het starten van je eigen project en beginnen met een standaard (…) helemaal aan het begin, gaat heel ver met het helpen van onderhoud, ontwikkeling en alles wat met het project te maken heeft!

Om iets te verduidelijken: ik denk eigenlijk niet dat het een goed idee is om een ​​naam van een klasse/wat dan ook te gebruiken in de STL opzettelijk en meer specifiek in plaats van. De string is de uitzondering (negeer de eerste, bovenstaande of tweede hier, woordspeling als het moet) voor mij omdat ik het idee van ‘String’ niet leuk vond.

Zoals het is, ben ik nog steeds erg bevooroordeeld ten opzichte van C en bevooroordeeld tegen C++. Spaar details, veel van waar ik aan werk past meer bij C (maar het was een goede oefening en een goede manier om mezelf te maken a. een andere taal te leren en b. probeer niet minder bevooroordeeld te zijn tegen object/klassen/etc, wat misschien beter gezegd is als minder bekrompen, minder arrogant en meer accepterend.). Maar wat is nuttig is wat sommigen al suggereerden: ik gebruik inderdaad lijst (het is vrij algemeen, nietwaar?), en sorteer (hetzelfde) om er twee te noemen die een naamconflict zouden veroorzaken als Ik zou using namespace std; gebruiken, en daarom geef ik er de voorkeur aan specifiek te zijn, de controle te hebben en te weten dat als ik van plan ben dat het standaardgebruik wordt, ik het zal moeten specificeren. Simpel gezegd: geen veronderstelling toegestaan.

En wat betreft het onderdeel maken van Boost’s regex van std. Ik doe dat voor toekomstige integratie en nogmaals, ik geef volledig toe dat dit vooringenomenheid is – ik denk niet dat het zo lelijk is als boost::regex:: .... Dat is inderdaad iets anders voor mij. Er zijn veel dingen in C++ die ik nog volledig moet accepteren in uiterlijk en methoden (een ander voorbeeld: variadische sjablonen versus var-argumenten [hoewel ik toegeef dat variadische sjablonen heel erg handig zijn!]). Zelfs degenen die ik accepteer, waren moeilijk, en ik heb nog steeds problemen met hen.


Antwoord 25

Uit mijn ervaring, als je meerdere bibliotheken hebt die bijvoorbeeld cout gebruiken, maar voor een ander doel, kun je de verkeerde cout gebruiken.

Als ik bijvoorbeeld typ, using namespace std; en using namespace otherlib; en gewoon cout typ (wat toevallig in beide), in plaats van std::cout (of 'otherlib::cout'), kunt u de verkeerde gebruiken en fouten krijgen. Het is veel effectiever en efficiënter om std::cout te gebruiken.


Antwoord 26

Ik denk niet dat het onder alle omstandigheden een slechte gewoonte is, maar je moet voorzichtig zijn als je het gebruikt. Als u een bibliotheek schrijft, moet u waarschijnlijk de operatoren voor bereikresolutie gebruiken met de naamruimte om te voorkomen dat uw bibliotheek botst met andere bibliotheken. Voor code op applicatieniveau zie ik er niets mis mee.


Antwoord 27

Met niet-gekwalificeerde geïmporteerde ID’s heeft u externe zoekhulpmiddelen zoals grep nodig om erachter te komen waar ID’s worden gedeclareerd. Dit maakt redeneren over de juistheid van programma’s moeilijker.


Antwoord 28

Het hangt af van waar het zich bevindt. Als het een algemene koptekst is, verkleint u de waarde van de naamruimte door deze samen te voegen met de algemene naamruimte. Houd er rekening mee dat dit een handige manier kan zijn om module-globalen te maken.


Antwoord 29

Dit is een slechte gewoonte, vaak bekend als wereldwijde vervuiling van de naamruimte. Er kunnen problemen optreden wanneer meer dan één naamruimte dezelfde functienaam met handtekening heeft, dan zal het voor de compiler dubbelzinnig zijn om te beslissen welke moet worden aangeroepen en dit kan allemaal worden vermeden wanneer u de naamruimte specificeert met uw functieaanroep zoals std::cout . Ik hoop dat dit helpt. 🙂


Antwoord 30

“Waarom is ‘namespace std;’ beschouwd als een slechte gewoonte in C++?”

Ik zeg het andersom: waarom wordt het typen van vijf extra tekens door sommigen als omslachtig beschouwd?

Bedenk b.v. het schrijven van een stukje numerieke software. Waarom zou ik zelfs overwegen om mijn globale naamruimte te vervuilen door algemene “std::vector” terug te brengen tot “vector” wanneer “vector” een van de belangrijkste concepten van het probleemdomein is?

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Other episodes