logo

Perché l'utilizzo dello spazio dei nomi std è considerato una cattiva pratica

La dichiarazione utilizzando lo spazio dei nomi std è generalmente considerata una cattiva pratica. L'alternativa a questa istruzione è specificare lo spazio dei nomi a cui appartiene l'identificatore utilizzando l'operatore di ambito(::) ogni volta che dichiariamo un tipo.
Sebbene l'affermazione ci risparmi dalla digitazione standard:: ogni volta che desideriamo accedere a una classe o a un tipo definito nello spazio dei nomi std, importa l'intero file standard namespace nello spazio dei nomi corrente del programma. Facciamo qualche esempio per capire perché questa potrebbe non essere una buona cosa
Diciamo che desideriamo utilizzare cout dallo spazio dei nomi std. Quindi scriviamo

Esempio 1:



CPP








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

>

>

Ora, in una fase successiva di sviluppo, desideriamo utilizzare un'altra versione di cout implementata in modo personalizzato in alcune librerie chiamate foo (ad esempio)

CPP




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

>

>

Notate ora che c'è un'ambiguità: a quale libreria punta cout? Il compilatore potrebbe rilevarlo e non compilare il programma. Nel peggiore dei casi, il programma potrebbe comunque compilarsi ma chiamare la funzione sbagliata, poiché non abbiamo mai specificato a quale spazio dei nomi appartenesse l'identificatore.
Gli spazi dei nomi sono stati introdotti in C++ per risolvere i conflitti dei nomi degli identificatori. Ciò garantisce che due oggetti possano avere lo stesso nome e tuttavia essere trattati in modo diverso se appartengono a spazi dei nomi diversi. Notate come in questo esempio si è verificato l'esatto contrario. Invece di risolvere un conflitto di nomi, creiamo effettivamente un conflitto di nomi.

Quando importiamo uno spazio dei nomi, essenzialmente inseriamo tutte le definizioni di tipo nell'ambito corrente. Lo spazio dei nomi std è enorme. Ha centinaia di identificatori predefiniti, quindi è possibile che uno sviluppatore possa trascurare il fatto che esiste un'altra definizione dell'oggetto previsto nella libreria std. Ignari di ciò, possono procedere a specificare la propria implementazione e aspettarsi che venga utilizzata nelle parti successive del programma. Pertanto esisterebbero due definizioni per lo stesso tipo nello spazio dei nomi corrente. Ciò non è consentito in C++ e, anche se il programma viene compilato, non c'è modo di sapere quale definizione viene utilizzata e dove.

La soluzione al problema è specificare esplicitamente a quale namespace appartiene il nostro identificatore utilizzando l'operatore scope (::). Quindi una possibile soluzione all'esempio precedente può essere

CPP




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

costanti Java
>

>

Ma dover scrivere standard:: ogni volta che definiamo un tipo è noioso. Inoltre, rende il nostro codice più peloso con molte definizioni di tipo e rende difficile la lettura del codice. Consideriamo ad esempio il codice per ottenere l'ora corrente nel programma
Esempio 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);>

>

come eseguire uno script in Linux
>

Il codice sorgente, pieno di definizioni di tipo lunghe e complicate, non è molto facile da leggere. Questo è qualcosa che gli sviluppatori cercano di evitare poiché per loro la manutenibilità del codice è principalmente importante.
Esistono alcuni modi per risolvere questo dilemma, ovvero specificare lo spazio dei nomi esatto senza sporcare il codice con parole chiave standard.

Prendi in considerazione l'utilizzo di typedef
typedef ci evita di scrivere lunghe definizioni di tipo. Nel nostro esempio 1, potremmo risolvere il problema utilizzando due typedef, uno per la libreria std e un altro per foo

CPP




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

>

>

Invece di importare interi spazi dei nomi, importa uno spazio dei nomi troncato
Nell'esempio 2 avremmo potuto importare solo lo spazio dei nomi chrono in 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);>

>

>

Possiamo anche usare l'istruzione per importare un singolo identificatore. Per importare solo std::cout potremmo usare

using std::cout;>

Se importi ancora interi spazi dei nomi, prova a farlo all'interno di funzioni o con un ambito limitato e non con un ambito globale.
Utilizzare l'istruzione using namespace std all'interno delle definizioni di funzioni o delle definizioni di classi e strutture. In tal modo le definizioni dello spazio dei nomi vengono importate in un ambito locale e almeno sappiamo dove potrebbero avere origine gli eventuali errori se si verificano.

CPP




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

>

come trasformare una stringa in un int

>

Conclusione.
Abbiamo discusso metodi alternativi per accedere a un identificatore da uno spazio dei nomi. In tutti i casi evitare di importare interi spazi dei nomi nel codice sorgente.
Sebbene le buone pratiche di codifica possano richiedere del tempo per essere apprese e sviluppate, generalmente danno i loro frutti a lungo termine. Scrivere un codice pulito, inequivocabile e robusto e privo di errori dovrebbe essere l'intento di qualsiasi sviluppatore di programmazione.