logo

Waarom het gebruik van naamruimtestd als een slechte praktijk wordt beschouwd

De verklaring namespace std; gebruiken wordt over het algemeen als een slechte praktijk beschouwd. Het alternatief voor deze instructie is om de naamruimte waartoe de identifier behoort op te geven met behulp van de scope-operator(::) telkens wanneer we een type declareren.
Hoewel de verklaring ons het typen bespaart soa:: telkens wanneer we toegang willen krijgen tot een klasse of type dat is gedefinieerd in de std-naamruimte, importeert het de volledige soa naamruimte in de huidige naamruimte van het programma. Laten we een paar voorbeelden nemen om te begrijpen waarom dit misschien niet zo goed is
Laten we zeggen dat we de cout uit de std-naamruimte willen gebruiken. Dus wij schrijven

Voorbeeld 1:



CPP




bevat python





#include> using> namespace> std;> > cout <<>' Something to Display'>;>

>

>

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

CPP




#include> #include> using> namespace> std;> > cout <<>' Something to display'>;>

>

>

Merk nu op dat er een dubbelzinnigheid is: naar welke bibliotheek verwijst cout? De compiler kan dit detecteren en het programma niet compileren. In het ergste geval kan het programma nog steeds compileren, maar de verkeerde functie aanroepen, omdat we nooit hebben gespecificeerd tot welke naamruimte de ID behoorde.
Naamruimten zijn in C++ geïntroduceerd om identificatienaamconflicten op te lossen. Dit zorgde ervoor dat twee objecten dezelfde naam konden hebben en toch verschillend konden worden behandeld als ze tot verschillende naamruimten behoorden. Merk op hoe precies het tegenovergestelde is gebeurd in dit voorbeeld. In plaats van een naamconflict op te lossen, creëren we feitelijk een naamconflict.

Wanneer we een naamruimte importeren, halen we in wezen alle typedefinities naar het huidige bereik. De std-naamruimte is enorm. Het heeft honderden vooraf gedefinieerde identificatiegegevens, dus het is mogelijk dat een ontwikkelaar over het hoofd ziet dat er een andere definitie van het beoogde object in de std-bibliotheek staat. Als ze zich hiervan niet bewust zijn, kunnen ze doorgaan met het specificeren van hun eigen implementatie en verwachten dat deze in latere delen van het programma zal worden gebruikt. Er zouden dus twee definities voor hetzelfde type in de huidige naamruimte bestaan. Dit is niet toegestaan ​​in C++, en zelfs als het programma compileert, kun je niet weten welke definitie waar wordt gebruikt.

De oplossing voor het probleem is om expliciet te specificeren tot welke naamruimte onze identificatie behoort met behulp van de scope-operator (::). Een mogelijke oplossing voor het bovenstaande voorbeeld kan dus zijn:

CPP




#include> #include> > // Use cout of std library> std::cout <<>'Something to display'>;> > // Use cout of foo library> foo::cout <>'Something to display'>;>

>

>

Maar moet typen soa:: elke keer dat we een type definiëren is vervelend. Het zorgt er ook voor dat onze code er hariger uitziet met veel typedefinities en maakt het moeilijk om de code te lezen. Denk bijvoorbeeld aan de code voor het ophalen van de huidige tijd in het programma
Voorbeeld 2:

CPP




#include> #include> > auto> start = std::chrono::high_performance_clock::now()> > // Do Something> > auto> stop> >= std::chrono::high_peformance_clock::now();> auto> duration> >= std::duration_cast(stop - start);>

>

>

De broncode die bezaaid is met ingewikkelde en lange typedefinities is niet erg gemakkelijk te lezen. Dit is iets wat ontwikkelaars proberen te vermijden, omdat onderhoudbaarheid van de code voor hen vooral belangrijk is.
Er zijn een paar manieren om dit dilemma op te lossen, dat wil zeggen het specificeren van de exacte naamruimte zonder code met standaard trefwoorden te vervuilen.

Overweeg het gebruik van typedefs
typedefs besparen ons het schrijven van lange typedefinities. In ons voorbeeld 1 zouden we het probleem kunnen oplossen met behulp van twee typedefs, één voor de std-bibliotheek en één voor foo

CPP




#include> #include> > typedef> std::cout cout_std;> typedef> foo::cout cout_foo;> > cout_std <<>'Something to write'>;> cout_foo <<>'Something to write'>;>

>

>

In plaats van volledige naamruimten te importeren, importeert u een afgeknotte naamruimte
In voorbeeld 2 hadden we alleen de chrono-naamruimte onder std kunnen importeren.

CPP




#include> #include> > // Import only the chrono namespace under std> using> std::chrono;> > auto> start = high_performance_clock::now();> > // Do Something> auto> stop = high_performance_clock::now();> auto> duration duration_cast(stop - start);>

>

>

We kunnen de instructie ook gebruiken voor het importeren van één enkele identificatie. Om alleen std::cout te importeren kunnen we gebruiken

using std::cout;>

Als u nog steeds volledige naamruimten importeert, probeer dit dan binnen functies of een beperkt bereik te doen en niet in een globaal bereik.
Gebruik de instructie 'using namespace std' binnen functiedefinities of klasse-, struct-definities. Daarbij worden de naamruimtedefinities geïmporteerd in een lokaal bereik, en weten we in ieder geval waar mogelijke fouten kunnen ontstaan ​​als ze zich voordoen.

CPP




#include> > // Avoid this> using> namespace> std;> > void> foo()> {> >// Inside function> >// Use the import statement inside limited scope> >using> namespace> std;> > >// Proceed with function> }>

>

>

Conclusie.
We hebben alternatieve methoden besproken voor toegang tot een ID vanuit een naamruimte. Vermijd in alle gevallen het importeren van volledige naamruimten in de broncode.
Hoewel het enige tijd kan duren om goede codeerpraktijken te leren en te ontwikkelen, betalen ze zich over het algemeen op de lange termijn terug. Het schrijven van schone, ondubbelzinnige en robuuste, foutloze code zou de bedoeling moeten zijn van elke programmeerontwikkelaar.