logo

Per què utilitzar namespace std es considera una mala pràctica

La declaració utilitzant l'espai de noms std generalment es considera una mala pràctica. L'alternativa a aquesta declaració és especificar l'espai de noms al qual pertany l'identificador mitjançant l'operador d'àmbit (::) cada vegada que declarem un tipus.
Encara que la declaració ens estalvia d'escriure std:: sempre que volem accedir a una classe o tipus definit a l'espai de noms std, importa la totalitat del fitxer std espai de noms a l'espai de noms actual del programa. Prenguem uns quants exemples per entendre per què això podria no ser tan bo
Diguem que volem utilitzar el cout de l'espai de noms std. Així que escrivim

Exemple 1:



nucli java

CPP








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

>

>

Ara, en una fase posterior de desenvolupament, volem utilitzar una altra versió de cout que s'implementa a mida en alguna biblioteca anomenada foo (per exemple)

CPP




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

>

>

Observeu que ara hi ha una ambigüitat, a quina biblioteca apunta Cout? El compilador pot detectar-ho i no compilar el programa. En el pitjor dels casos, el programa encara pot compilar però crida a la funció incorrecta, ja que mai hem especificat a quin espai de noms pertanyia l'identificador.
Els espais de noms es van introduir a C++ per resoldre els conflictes de noms d'identificador. Això assegurava que dos objectes poguessin tenir el mateix nom i, tanmateix, ser tractats de manera diferent si pertanyien a espais de noms diferents. Observeu com ha passat exactament el contrari en aquest exemple. En lloc de resoldre un conflicte de nom, en realitat creem un conflicte de nom.

Quan importem un espai de noms, bàsicament estem incorporant totes les definicions de tipus a l'àmbit actual. L'espai de noms std és enorme. Té centenars d'identificadors predefinits, de manera que és possible que un desenvolupador passi per alt el fet que hi ha una altra definició del seu objecte previst a la biblioteca std. Sense saber-ho, poden procedir a especificar la seva pròpia implementació i esperar que s'utilitzi en parts posteriors del programa. Per tant, hi hauria dues definicions per al mateix tipus a l'espai de noms actual. Això no està permès en C++, i fins i tot si el programa compila, no hi ha manera de saber quina definició s'està utilitzant on.

La solució al problema és especificar explícitament a quin espai de noms pertany el nostre identificador mitjançant l'operador d'àmbit (::). Per tant, una possible solució a l'exemple anterior pot ser

CPP




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

>

>

Però haver de escriure std:: cada vegada que definim un tipus és tediós. També fa que el nostre codi sembli més pelut amb moltes definicions de tipus i dificulta la lectura del codi. Penseu, per exemple, en el codi per obtenir l'hora actual del programa
Exemple 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);>

>

>

El codi font que està ple de definicions complicades i llargues no és molt fàcil de llegir. Això és una cosa que els desenvolupadors busquen evitar, ja que el manteniment del codi és principalment important per a ells.
Hi ha algunes maneres de resoldre aquest dilema, és a dir, especificar l'espai de nom exacte sense llençar codi amb paraules clau std.

Penseu en utilitzar typedefs
els typedefs ens eviten escriure definicions de tipus llargues. Al nostre exemple 1, podríem resoldre el problema utilitzant dos tipus de definicions un per a la biblioteca std i un altre per a foo

CPP




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

>

>

En lloc d'importar espais de noms sencers, importeu un espai de noms truncat
A l'exemple 2 podríem haver importat només l'espai de noms crono sota std.

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

>

>

També podem utilitzar la instrucció per importar un únic identificador. Per importar només std::cout podríem utilitzar

java vs c++
using std::cout;>

Si encara importeu espais de noms sencers, proveu de fer-ho dins de funcions o d'abast limitat i no a l'àmbit global.
Utilitzeu la instrucció using namespace std dins de definicions de funció o definicions de classe i estructura. En fer-ho, les definicions de l'espai de noms s'importen a un àmbit local, i almenys sabem on es poden originar possibles errors si sorgeixen.

CPP




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

>

>

Conclusió.
Hem parlat de mètodes alternatius per accedir a un identificador des d'un espai de noms. En tots els casos, eviteu importar espais de noms sencers al codi font.
Tot i que les bones pràctiques de codificació poden trigar un temps a aprendre i desenvolupar-se, generalment es beneficien a llarg termini. Escriure codi net, inequívoc i sense errors ha de ser la intenció de qualsevol desenvolupador de programació.