Zunächst einige Begriffe:
- using-Deklaration :
using std::vector;
- using-Direktive :
using namespace std;
Ich denke, dass die Verwendung von using-Direktiven in Ordnung ist, solange sie nicht im globalen Bereich einer Header-Datei verwendet werden. Also haben
using namespace std;
in Ihrer CPP-Datei ist kein wirkliches Problem, und wenn sich herausstellt, dass es vollständig unter Ihrer Kontrolle steht (und es kann auf Wunsch sogar auf bestimmte Blöcke beschränkt werden). Ich sehe keinen besonderen Grund, den Code mit einer Menge zu überladenstd:: Qualifikationsmerkmalen zu - es wird nur ein Haufen visueller Geräusche. Wenn Sie jedoch nicht eine ganze Reihe von Namen aus dem stdNamespace in Ihrem Code verwenden, sehe ich auch kein Problem darin, die Direktive wegzulassen. Es ist eine Tautologie - wenn die Richtlinie nicht erforderlich ist, muss sie nicht verwendet werden.
Ebenso, wenn Sie mit ein paar using-Deklarationen (anstelle von using-Direktiven ) für bestimmte Typen in derstd Namespace , gibt es keinen Grund, warum Sie nicht nur diese spezifischen Namen in den aktuellen Namespace einfügen sollten. Aus dem gleichen Grund denke ich, dass es verrückt und ein Aufwand für die Buchhaltung wäre, 25 oder 30 Verwendungserklärungen zu haben, wenn eine einzige Verwendungsrichtlinie den Trick genauso gut machen würde.
Es ist auch gut im Auge zu behalten , dass es Zeiten , in denen Sie müssen eine using-Deklaration verwenden. Siehe Scott Meyers '"Punkt 25: Unterstützung für einen nicht werfenden Swap in Betracht ziehen" aus Effective C ++, Third Edition. Damit eine generische Funktion mit Vorlagen die 'beste' Swap-Methode für einen parametrisierten Typ verwenden kann, müssen Sie eine using-Deklaration und eine argumentabhängige Suche (auch bekannt als ADL- oder Koenig-Lookup) verwenden:
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>()
// ...
}
Ich denke, wir sollten uns die gemeinsamen Redewendungen für verschiedene Sprachen ansehen, die Namespaces in erheblichem Maße nutzen. Beispielsweise verwenden Java und C # in großem Umfang Namespaces (wahrscheinlich mehr als C ++). Die gebräuchlichste Art und Weise, wie Namen in Namespaces in diesen Sprachen verwendet werden, besteht darin, sie massenhaft mit dem Äquivalent einer using-Direktive in den aktuellen Geltungsbereich zu bringen. Dies führt nicht zu weit verbreiteten Problemen, und die wenigen Male, bei denen es sich um ein Problem handelt, werden auf Ausnahmebasis behandelt, indem die betreffenden Namen über vollständig qualifizierte Namen oder durch Aliasing behandelt werden - genau wie dies in C ++ möglich ist.
Herb Sutter und Andrei Alexandrescu haben dies in "Punkt 59: Schreiben Sie keine Namespace-Verwendungen in eine Header-Datei oder vor einem #include" ihres Buches C ++ Coding Standards: 101 Regeln, Richtlinien und Best Practices zu sagen:
Kurz gesagt: Sie können und sollten den Namespace verwenden, indem Sie Deklarationen und Anweisungen in Ihren Implementierungsdateien nach #includeAnweisungen großzügig verwenden, und sich dabei wohl fühlen. Trotz wiederholter gegenteiliger Behauptungen ist der Namespace, der Deklarationen und Anweisungen verwendet, nicht böse und macht den Zweck von Namespaces nicht zunichte. Sie machen vielmehr Namespaces nutzbar.
Stroupstrup wird in "The C ++ Programming Language, Third Edition" häufig mit den Worten "Verschmutzen Sie nicht den globalen Namespace" zitiert. Er sagt das tatsächlich (C.14 [15]), bezieht sich aber auf Kapitel C.10.1, in dem er sagt:
Eine using-Deklaration fügt einem lokalen Bereich einen Namen hinzu. Eine using-Direktive nicht; Es macht Namen einfach in dem Bereich zugänglich, in dem sie deklariert wurden. Beispielsweise:
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
}
Ein lokal deklarierter Name (entweder durch eine normale Deklaration oder durch eine using-Deklaration deklariert) verbirgt nichtlokale Deklarationen mit demselben Namen, und alle illegalen Überladungen des Namens werden zum Zeitpunkt der Deklaration erkannt.
Beachten Sie den Mehrdeutigkeitsfehler für k++in
f1(). Globale Namen werden nicht vor Namen aus Namespaces bevorzugt, die im globalen Bereich zugänglich gemacht werden. Dies bietet einen erheblichen Schutz vor versehentlichen Namenskonflikten und stellt - was wichtig ist - sicher, dass die Verschmutzung des globalen Namespace keine Vorteile bringt.
Wenn Bibliotheken, die viele Namen deklarieren, über using-Direktiven zugänglich gemacht werden, ist es ein wesentlicher Vorteil, dass Zusammenstöße nicht verwendeter Namen nicht als Fehler betrachtet werden.
...
Ich hoffe, dass die Verwendung globaler Namen in neuen Programmen mit Namespaces im Vergleich zu herkömmlichen C- und C ++ - Programmen radikal abnimmt. Die Regeln für Namespaces wurden speziell entwickelt, um einem "faulen" Benutzer globaler Namen keine Vorteile gegenüber jemandem zu verschaffen, der darauf achtet, den globalen Bereich nicht zu verschmutzen.
Und wie hat man den gleichen Vorteil wie ein "fauler Benutzer globaler Namen"? Durch die Nutzung der using-Direktive, die Namen in einem Namespace sicher für den aktuellen Bereich verfügbar macht.
Beachten Sie, dass es einen Unterschied gibt - Namen im stdNamespace, die einem Bereich mit der richtigen Verwendung einer using-Direktive (durch Platzieren der Direktive nach dem #includes) zur Verfügung gestellt werden , verschmutzen den globalen Namespace nicht. Es geht nur darum, diese Namen leicht verfügbar zu machen und sie weiterhin vor Zusammenstößen zu schützen.