Innanzitutto, un po 'di terminologia:
- dichiarazione-d'uso :
using std::vector;
- using-Directive :
using namespace std;
Penso che l'uso delle direttive using vada bene, purché non vengano utilizzate nell'ambito globale in un file di intestazione. Quindi avere
using namespace std;
nel tuo file .cpp non è davvero un problema e, se risulta essere, è completamente sotto il tuo controllo (e può anche essere limitato a blocchi particolari, se lo desideri). Non vedo alcun motivo particolare per ingombrare il codice con una sfilza di std::
qualificatori: diventa solo un mucchio di rumore visivo. Tuttavia, se non stai utilizzando un sacco di nomi dal filestd
spazio nomi nel tuo codice, non vedo alcun problema anche nel tralasciare la direttiva. È una tautologia: se la direttiva non è necessaria, non è necessario usarla.
Allo stesso modo, se riesci a cavartela con alcune dichiarazioni using (invece di direttive using ) per tipi specifici nello std
spazio dei nomi, non c'è motivo per cui non dovresti avere solo quei nomi specifici portati nello spazio dei nomi corrente. Allo stesso modo, penso che sarebbe folle e una seccatura per la contabilità avere 25 o 30 dichiarazioni d'uso quando una singola direttiva d'uso farebbe altrettanto bene.
È anche utile tenere presente che ci sono momenti in cui è necessario utilizzare una dichiarazione di utilizzo. Fare riferimento all '"Item 25: Considerate support for a non-throwing swap" di Scott Meyers da Effective C ++, Third Edition. Per fare in modo che una funzione generica basata su modelli utilizzi il metodo di scambio "migliore" per un tipo parametrizzato, è necessario utilizzare una dichiarazione using e una ricerca dipendente dall'argomento (alias ADL o ricerca Koenig):
template< typename T >
void foo( T& x, T& y)
{
using std::swap; // makes std::swap available in this function
// do stuff...
swap( x, y); // will use a T-specific swap() if it exists,
// otherwise will use std::swap<T>()
// ...
}
Penso che dovremmo esaminare gli idiomi comuni per varie lingue che fanno un uso significativo degli spazi dei nomi. Ad esempio, Java e C # utilizzano gli spazi dei nomi in larga misura (probabilmente più del C ++). Il modo più comune in cui i nomi all'interno degli spazi dei nomi vengono usati in quei linguaggi è portarli in massa nell'ambito corrente con l'equivalente di una direttiva using. Ciò non causa problemi diffusi e le poche volte in cui si tratta di un problema vengono gestiti in base a "eccezioni" trattando i nomi in questione tramite nomi completi o mediante aliasing, proprio come si può fare in C ++.
Herb Sutter e Andrei Alexandrescu hanno questo da dire in "Item 59: Don't write namespace usings in a header file or before an #include" of their book, C ++ Coding Standards: 101 Rules, Guidelines, and Best Practices:
In breve: puoi e dovresti usare lo spazio dei nomi usando le dichiarazioni e le direttive liberamente nei tuoi file di implementazione dopo le #include
direttive e sentirti bene al riguardo. Nonostante ripetute affermazioni contrarie, le dichiarazioni e le direttive che utilizzano lo spazio dei nomi non sono malvagi e non annullano lo scopo degli spazi dei nomi. Piuttosto, sono ciò che rende utilizzabili gli spazi dei nomi.
Stroupstrup è spesso citato come dicendo: "Non inquinare lo spazio dei nomi globale", in "The C ++ Programming Language, Third Edition". Lo dice infatti (C.14 [15]), ma fa riferimento al capitolo C.10.1 dove dice:
Una dichiarazione using aggiunge un nome a un ambito locale. Una direttiva using non lo fa; semplicemente rende i nomi accessibili nell'ambito in cui sono stati dichiarati. Per esempio:
namespaceX {
int i , j , k ;
}
int k ;
void f1()
{
int i = 0 ;
using namespaceX ; // make names from X accessible
i++; // local i
j++; // X::j
k++; // error: X::k or global k ?
::k ++; // the global k
X::k ++; // X’s k
}
void f2()
{
int i = 0 ;
using X::i ; // error: i declared twice in f2()
using X::j ;
using X::k ; // hides global k
i++;
j++; // X::j
k++; // X::k
}
Un nome dichiarato localmente (dichiarato da una dichiarazione ordinaria o da una dichiarazione di utilizzo) nasconde dichiarazioni non locali con lo stesso nome e qualsiasi sovraccarico illegale del nome viene rilevato al momento della dichiarazione.
Nota l'errore di ambiguità per k++
in
f1()
. Ai nomi globali non viene data la preferenza rispetto ai nomi degli spazi dei nomi resi accessibili nell'ambito globale. Ciò fornisce una protezione significativa contro i conflitti di nome accidentali e, cosa importante, garantisce che non ci siano vantaggi da ottenere dall'inquinamento dello spazio dei nomi globale.
Quando le librerie che dichiarano molti nomi sono rese accessibili tramite le direttive using, è un vantaggio significativo che i conflitti di nomi inutilizzati non siano considerati errori.
...
Spero di vedere una riduzione radicale nell'uso dei nomi globali nei nuovi programmi che utilizzano spazi dei nomi rispetto ai tradizionali programmi C e C ++. Le regole per gli spazi dei nomi sono state create appositamente per non dare vantaggi a un utente "pigro" di nomi globali rispetto a qualcuno che si prende cura di non inquinare l'ambito globale.
E come si ha lo stesso vantaggio di un "utente pigro di nomi globali"? Sfruttando la direttiva using, che rende in modo sicuro i nomi in uno spazio dei nomi disponibili per l'ambito corrente.
Si noti che c'è una distinzione: i nomi nello std
spazio dei nomi resi disponibili a un ambito con l'uso corretto di una direttiva using (inserendo la direttiva dopo #includes
) non inquinano lo spazio dei nomi globale. Sta solo rendendo quei nomi disponibili facilmente e con una protezione continua contro gli scontri.