GeeksforGeeks
On ianuarie 16, 2022 by adminDeclarația using namespace std este în general considerată o practică proastă. Alternativa la această afirmație este de a specifica namespace-ul căruia îi aparține identificatorul folosind operatorul scope(::) de fiecare dată când declarăm un tip.
Deși declarația ne scutește de tastarea std:: ori de câte ori dorim să accesăm o clasă sau un tip definit în spațiul de nume std, aceasta importă întregul spațiu de nume std în spațiul de nume curent al programului. Să luăm câteva exemple pentru a înțelege de ce acest lucru ar putea să nu fie un lucru atât de bun
Să spunem că dorim să folosim cout din spațiul de nume std. Așadar, scriem
Exemplu 1:
#include <iostream>
using
. namespace
std;
cout <<
" Something to Display"
;
Acum, într-un stadiu mai târziu de dezvoltare, dorim să folosim o altă versiune de cout care este implementată personalizat într-o bibliotecă numită „foo” (de exemplu)
.
#include <foo.h>
#include <iostream>
using
namespace
std;
cout <<
" Something to display"
;
Observați cum există o ambiguitate, către ce bibliotecă indică cout? Compilatorul poate să detecteze acest lucru și să nu compileze programul. În cel mai rău caz, programul poate totuși să compileze, dar să apeleze funcția greșită, deoarece nu am specificat niciodată la ce spațiu de nume aparținea identificatorul.
Spațiile de nume au fost introduse în C++ pentru a rezolva conflictele de nume ale identificatorilor. Acest lucru a asigurat că două obiecte pot avea același nume și totuși să fie tratate diferit dacă aparțin unor spații de nume diferite. Observați cum s-a întâmplat exact opusul în acest exemplu. În loc să rezolvăm un conflict de nume, noi creăm de fapt un conflict de nume.
Când importăm un spațiu de nume, în esență tragem toate definițiile de tip în domeniul curent. Spațiul de nume std este imens. Are sute de identificatori predefiniți, astfel încât este posibil ca un dezvoltator să treacă cu vederea faptul că există o altă definiție a obiectului dorit în biblioteca std. Fără a fi conștient de acest lucru, acesta poate continua să își specifice propria implementare și să se aștepte 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 compilează, nu există nici o modalitate de a ști care definiție este folosită unde.
Soluția problemei este de a specifica în mod explicit din ce spațiu de nume face parte identificatorul nostru folosind operatorul scope (::). Astfel, o posibilă soluție la exemplul de mai sus poate fi
#include <foo>
#include <iostream>
std::cout <<
"Something to display"
;
foo::cout <
"Something to display"
;
Dar trebuind să tastezi std:: de fiecare dată când definim un tip este plictisitor. De asemenea, ne face codul să arate mai păros cu o mulțime de definiții de tip și face dificilă citirea codului. Luați în considerare, de exemplu, codul pentru obținerea orei curente în programul
Exemplu 2:
.
#include <chrono>
#include <iostream>
auto
start = std::chrono::high_performance_clock::now()
auto
stop
= std::chrono::high_peformance_clock::now();
auto
duration
= std::duration_cast<std::chrono::milliseconds>(stop - start);
Codul sursă care este presărat cu definiții de tip complicate și lungi nu este foarte ușor de citit. Acesta este un lucru pe care dezvoltatorii caută să îl evite, deoarece întreținerea codului este în principal importantă pentru ei.
Există câteva modalități de a rezolva această dilemă, și anume specificarea exactă a spațiului de nume fără a împovăra codul cu cuvinte cheie std.
Considerați utilizarea typedefs
typedefs ne salvează de la scrierea unor definiții de tip lungi. În exemplul nostru 1, am putea rezolva problema folosind două typedefs, unul pentru biblioteca std și altul pentru foo
#include <foo>
#include <iostream>
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.
.
.
#include <chrono>
#include <iostream>
using
std::chrono;
auto
start = high_performance_clock::now();
auto
stop = high_performance_clock::now();
auto
duration duration_cast<milliseconds>(stop - start);
De asemenea, putem utiliza declarația pentru a importa un singur identificator. Pentru a importa doar std::cout am putea folosi
using std::cout;
using std::cout;
Dacă totuși importați spații de nume întregi, încercați să o faceți în interiorul funcțiilor sau în domeniul de aplicare limitat și nu în domeniul de aplicare global.
Utilizați instrucțiunea „using namespace std” în interiorul definițiilor de funcții sau al definițiilor de clase, structuri. Procedând astfel, definițiile spațiului de nume sunt importate într-un domeniu de aplicare local și cel puțin știm de unde pot proveni eventualele erori în cazul în care acestea apar.
#include <isotream>
using
namespace
std;
void
foo()
{
using
namespace
std;
}
Concluzie.
Am discutat metode alternative de accesare a unui identificator dintr-un spațiu de nume. În toate cazurile, evitați să importați spații de nume întregi în codul sursă.
Deși bunele practici de codare pot necesita ceva timp pentru a fi învățate și dezvoltate, în general, acestea dau roade pe termen lung. Scrierea unui cod curat, lipsit de ambiguitate și robust, fără erori, ar trebui să fie intenția oricărui dezvoltator de programare.
Lasă un răspuns