logo

De ce utilizarea namespace std este considerată o practică proastă

Declaratia folosind namespace std este în general considerată o practică proastă. Alternativa la această declarație este să specificați spațiul de nume căruia îi aparține identificatorul utilizând operatorul scope(::) de fiecare dată când declarăm un tip.
Deși afirmația ne scutește de la tastare std:: ori de câte ori dorim să accesăm o clasă sau un tip definit în spațiul de nume std, acesta importă întregul std namespace în spațiul de nume curent al programului. Să luăm câteva exemple pentru a înțelege de ce s-ar putea să nu fie un lucru atât de bun
Să presupunem că dorim să folosim cout din spațiul de nume std. Așa că scriem

Exemplul 1:



CPP

plutind css








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

>

>

Acum, într-o etapă ulterioară de dezvoltare, dorim să folosim o altă versiune de cout care este implementată personalizat într-o bibliotecă numită foo (de exemplu)

CPP




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

>

>

Observați că acum există o ambiguitate, spre care bibliotecă se referă Cout? Compilatorul poate detecta acest lucru și nu compila programul. În cel mai rău caz, programul poate să compileze, dar să apeleze funcția greșită, deoarece nu am specificat niciodată cărui spațiu de nume aparținea identificatorul.
Spațiile de nume au fost introduse în C++ pentru a rezolva conflictele de nume de identificare. Acest lucru a asigurat că două obiecte pot avea același nume și totuși pot fi tratate diferit dacă aparțin unor spații de nume diferite. Observați cum sa întâmplat exact opusul în acest exemplu. În loc să rezolvăm un conflict de nume, de fapt creăm un conflict de denumire.

Când importăm un spațiu de nume, în esență, tragem toate definițiile de tip în domeniul curent. Spațiul de nume standard este uriaș. Are sute de identificatori predefiniti, deci este posibil ca un dezvoltator să treacă cu vederea faptul că există o altă definiție a obiectului dorit în biblioteca standard. Neștiind acest lucru, ei pot continua să își specifice propria implementare și se așteaptă ca aceasta să fie utilizată în părțile ulterioare ale programului. Astfel, ar exista două definiții pentru același tip în spațiul de nume curent. Acest lucru nu este permis în C++ și, chiar dacă programul se compilează, nu există nicio modalitate de a ști care definiție este folosită unde.

Soluția problemei este să specificați în mod explicit cărui spațiu de nume îi aparține identificatorul nostru, folosind operatorul de aplicare (::). Astfel, o posibilă soluție la exemplul de mai sus poate fi

CPP


șiruri de caractere concatenate bash



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

>

>

Dar trebuie să tastați std:: de fiecare dată când definim un tip este plictisitor. De asemenea, face codul nostru să pară mai păros cu o mulțime de definiții de tip și îngreunează citirea codului. Luați în considerare, de exemplu, codul pentru obținerea orei curente în program
Exemplul 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);>

>

>

Codul sursă care este plin de definiții complicate și lungi nu este foarte ușor de citit. Este ceva ce dezvoltatorii încearcă să evite, deoarece mentenabilitatea codului este importantă în principal pentru ei.
Există câteva modalități de a rezolva această dilemă, adică specificați spațiul de nume exact fără a împrăștia codul cu cuvinte cheie std.

Luați în considerare utilizarea typedefs
Typedef-urile ne scutesc de a scrie definiții de tip lung. În exemplul nostru 1, am putea rezolva problema folosind două definiții de tip, unul pentru biblioteca std și altul pentru foo

CPP




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

>

>

În loc să importați spații de nume întregi, importați un spațiu de nume trunchiat
În exemplul 2 am fi putut importa doar spațiul de nume chrono sub std.

afișați aplicațiile ascunse

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

>

>

De asemenea, putem folosi instrucțiunea pentru a importa un singur identificator. Pentru a importa doar std::cout am putea folosi

using std::cout;>

Dacă încă importați spații de nume întregi, încercați să faceți acest lucru în interiorul funcțiilor sau în domeniul limitat și nu în domeniul global.
Utilizați instrucțiunea using namespace std în cadrul definițiilor de funcție sau ale definițiilor de clasă și struct. Procedând astfel, definițiile spațiului de nume sunt importate într-un domeniu local și cel puțin știm de unde pot apărea erori posibile dacă apar.

CPP




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

>

>

Concluzie.
Am discutat despre metode alternative de accesare a unui identificator dintr-un spațiu de nume. În toate cazurile, evitați importarea spațiilor de nume întregi în codul sursă.
În timp ce bunele practici de codificare pot dura ceva timp pentru a învăța și a se dezvolta, în general, ele dau rezultate pe termen lung. Scrierea unui cod curat, clar și robust, fără erori ar trebui să fie intenția oricărui dezvoltator de programare.