“Using namespace” nelle intestazioni c ++

In tutti i nostri corsi di c ++, tutti gli insegnanti using namespace std; sempre using namespace std; subito dopo #include i file .h . Questo mi sembra pericoloso da allora, includendo quell’intestazione in un altro programma, otterrò lo spazio dei nomi importato nel mio programma, forse senza rendermene conto, intendendolo o volendolo (l’inclusione dell’intestazione può essere molto profondamente annidata).

Quindi la mia domanda è doppia: ho ragione che using namespace non dovrebbe essere usato nei file di intestazione, e / o c’è un modo per annullarlo, qualcosa come:

 //header.h using namespace std { . . . } 

Un’altra domanda segue le stesse linee: Se un file di intestazione #include tutte le intestazioni a cui corrisponde il file .cpp corrispondente, solo quelle necessarie per le definizioni dell’intestazione e lascia il file .cpp #include il resto, o none e dichiara tutto ha bisogno di extern ?
Il ragionamento alla base della domanda è lo stesso di sopra: non voglio sorprese quando .h file .h .

Inoltre, se ho ragione, è un errore comune? Intendo nella programmazione del mondo reale e in progetti “reali” là fuori.

Grazie.

NON si deve assolutamente usare l’ using namespace nelle intestazioni proprio per la ragione che si dice, che può cambiare inaspettatamente il significato del codice in qualsiasi altro file che include quell’intestazione. Non c’è modo di annullare un using namespace che è un’altra ragione per cui è così pericoloso. Solitamente uso solo grep o simili per assicurarmi che l’ using namespace non venga richiamato nelle intestazioni piuttosto che provare qualcosa di più complicato. Probabilmente anche i controllori di codice statici lo segnalano.

L’intestazione dovrebbe includere solo le intestazioni da compilare. Un modo semplice per far rispettare questo è sempre includere l’intestazione di ogni file sorgente come prima cosa, prima di qualsiasi altra intestazione. Quindi il file di origine non riuscirà a compilare se l’intestazione non è autonoma. In alcuni casi, ad esempio facendo riferimento alle classi di dettaglio dell’implementazione all’interno di una libreria, è ansible utilizzare le dichiarazioni di inoltro invece di #include perché si ha il pieno controllo sulla definizione di tale class dichiarata in avanti.

Non sono sicuro che lo chiamerei comune, ma si presenta sicuramente una volta ogni tanto, solitamente scritto da nuovi programmatori che non sono consapevoli delle conseguenze negative. In genere solo un po ‘di educazione sui rischi si prende cura di eventuali problemi dal momento che è relativamente semplice da risolvere.

Articolo 59 di Sutter and Alexandrescu “C ++ Coding Standards: 101 Rules, Guidelines and Best Practices”:

  1. Non scrivere gli usi dello spazio dei nomi in un file di intestazione o prima di un #include. 108

I titoli di tutte le linee guida sono disponibili all’indirizzo http://www.gotw.ca/publications/c++cs.htm , ma i dettagli sono una lettura obbligata per gli sviluppatori C ++.

Devi fare attenzione quando includi le intestazioni all’interno delle intestazioni. Nei progetti di grandi dimensioni, può creare una catena di dipendenze molto aggrovigliata che innesca ricostruzioni più lunghe / più lunghe di quelle effettivamente necessarie. Dai un’occhiata a questo articolo e al suo follow-up per saperne di più sull’importanza di una buona struttura fisica nei progetti C ++.

Dovresti includere solo intestazioni all’interno di un’intestazione quando assolutamente necessario (ogni volta che è necessaria la definizione completa di una class) e utilizzare la dichiarazione diretta ovunque sia ansible (quando la class è richiesta è un puntatore o un riferimento).

Per quanto riguarda gli spazi dei nomi, tendo ad usare lo scope dei nomi esplicito nei miei file header e inserisco solo uno using namespace miei file cpp.

Controlla gli standard di codifica di Goddard Space Flight Center (per C e C ++). Questo risulta essere un po ‘più difficile di un tempo – vedi le risposte aggiornate alle domande SO:

  • Dovrei usare # include nelle intestazioni
  • Intestazioni autosufficienti in C e C ++

Lo standard di codifica GSFC C ++ dice:

§3.3.7 Ogni file di intestazione deve #include i file che deve compilare, piuttosto che forzare gli utenti a #include i file necessari. #includes devono essere limitati a ciò di cui ha bisogno l’intestazione; altri #includes dovrebbero essere inseriti nel file sorgente.

La prima delle domande con riferimenti incrociati ora include una citazione dello standard di codifica C GSFC e la motivazione, ma la sostanza finisce per essere la stessa.

Hai ragione che using namespace nell’intestazione è pericoloso. Non so come annullare. È facile da rilevare, ma cerca solo using namespace nei file di intestazione. Per l’ultimo motivo è raro nei progetti reali. Collaboratori più esperti si lamenteranno presto se qualcuno fa qualcosa del genere.

Nei progetti reali le persone cercano di ridurre al minimo la quantità di file inclusi, perché meno si include la più veloce compila. Questo fa risparmiare tempo a tutti. Tuttavia se il file di intestazione presuppone che qualcosa debba essere incluso prima di esso, dovrebbe includerlo esso stesso. In caso contrario, le intestazioni non sono autonome.

Hai ragione. E ogni file dovrebbe includere solo le intestazioni necessarie a quel file. Per quanto riguarda “sta facendo cose sbagliate comuni nei progetti del mondo reale?” – Oh si!

Come tutte le cose in programmazione, il pragmatismo dovrebbe conquistare il dogmatismo, IMO.

Finché si prende la decisione a livello di progetto (“Il nostro progetto utilizza ampiamente STL, e non vogliamo dover anteporre tutto a std ::.”), Non vedo il problema con esso. L’unica cosa che stai rischiando è il nome collisioni, dopo tutto, e con l’ubiquità di STL è improbabile che sia un problema.

D’altra parte, se si trattasse di una decisione da parte di uno sviluppatore in un singolo file di intestazione (non privato), posso vedere come ciò potrebbe generare confusione tra la squadra e dovrebbe essere evitato.

Credo che tu possa usare “usare” in modo sicuro le intestazioni C ++ se scrivi le tue dichiarazioni in uno spazio dei nomi annidato come questo:

 namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED { /*using statements*/ namespace DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED { /*declarations*/ } } using namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED::DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED; 

Questo dovrebbe includere solo le cose dichiarate in “DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED” senza gli spazi dei nomi usati. L’ho provato sul compilatore mingw64.

Riguardo a “C’è un modo per annullare [una dichiarazione using ]?”

Penso che sia utile sottolineare che l’ using dichiarazioni è influenzato dall’ambito.

 #include  { // begin a new scope with { using namespace std; vector myVector; // std::vector is used } // end the scope with } vector myOtherVector; // error vector undefined std::vector mySTDVector // no error std::vector is fully qualified 

Così efficacemente sì. Limitando l’ambito della dichiarazione d’ using , il suo effetto dura solo all’interno di tale ambito; è “annullato” quando termina quello scopo.

Quando la dichiarazione using viene dichiarata in un file al di fuori di qualsiasi altro scope ha scope-scope e influenza tutto in quel file.

Nel caso di un file di intestazione, se la dichiarazione using è nello scope-scope questo si estenderà all’ambito di ogni file in cui è inclusa l’intestazione.