Warum werden unbenannte Namespaces verwendet und welche Vorteile haben sie?

Ich bin gerade einem neuen C ++ – Softwareprojekt beigetreten und versuche das Design zu verstehen. Das Projekt verwendet häufig unbenannte Namespaces. In einer classndefinitionsdatei kann beispielsweise Folgendes auftreten:

// newusertype.cc namespace { const int SIZE_OF_ARRAY_X; const int SIZE_OF_ARRAY_Y; bool getState(userType*,otherUserType*); } newusertype::newusertype(...) {... 

Welche Designüberlegungen können dazu führen, dass ein unbenannter Namespace verwendet wird? Was sind die Vor- und Nachteile?

Solutions Collecting From Web of "Warum werden unbenannte Namespaces verwendet und welche Vorteile haben sie?"

(Im Folgenden sind die durchgestrichenen Dinge Dinge, die nicht mehr auf C ++ 11 zutreffen, aber auf C ++ 03 zutreffen. C ++ 11 macht fast keine Unterschiede mehr (wenn ja, sind sie nur Sprache) Anwaltsunterschiede, an die ich mich nicht erinnern kann.).

Unbenannte Namespaces sind ein Dienstprogramm, um einen Bezeichner effektiv lokal zu übersetzen. Sie verhalten sich so, als würden Sie pro Übersetzungseinheit für einen Namensraum einen eindeutigen Namen wählen:

 namespace unique { /* empty */ } using namespace unique; namespace unique { /* namespace body. stuff in here */ } 

Der zusätzliche Schritt, der den leeren Body verwendet, ist wichtig, daher können Sie bereits innerhalb des Namespace-Body auf Bezeichner wie ::name verweisen, die in diesem Namespace definiert sind, da die using-statement bereits stattgefunden hat.

Das bedeutet, dass Sie freie functionen aufrufen können, die beispielsweise in mehreren Übersetzungseinheiten enthalten sein können, und sie werden bei der Verknüpfungszeit nicht kollidieren, da sie alle aufgrund ihres eindeutigen Namensraums einen eindeutigen Namen haben . Der Effekt ist fast identisch mit der Verwendung des static Schlüsselworts in C, das Sie in die Deklaration von Bezeichnern einfügen können. static auf diese Weise verwendete static ist in C ++ veraltet, da unbenannte Namespaces eine bessere Alternative darstellen, da es sogar möglich ist, eine Typübersetzungseinheit lokal zu erstellen.

 namespace { int a1; } static int a2; 

Beide sind lokal übersetzt und kollidieren nicht zum Zeitpunkt der Verbindung. Der Unterschied ist, dass das a1 im anonymen Namespace nur einen eindeutigen Namen erhält. Es hat immer noch eine externe Verknüpfung und kann in die Symboltabelle der zu erstellenden Objektdatei exportiert werden. Dies wird wichtig, wenn Sie seine Adresse als Template-Argument verwenden möchten:

 template struct sample { }; // OK - a1 has external linkage sample< &a1> s1; // NOT OK - translation unit locality is done by giving a2 internal linkage. sample< &a2> s2; 

Template-Parameter müssen extern verlinkt sein, in diesem Fall muss der Identifier in einen anonymen Namensraum gestellt werden.

Lesen Sie den ausgezeichneten Artikel bei comeau-computing. Warum wird ein unbenannter Namespace anstelle von statisch verwendet? .

Etwas in einem anonymen Namespace bedeutet, dass es lokal zu dieser Übersetzungseinheit (.cpp-Datei und allen zugehörigen Includes) ist. Dies bedeutet, dass wenn ein anderes Symbol mit dem gleichen Namen an anderer Stelle definiert wird, keine Verletzung der One Definition Rule (ODR) vorliegt.

Dies ist das Gleiche wie die C-Art, eine statische globale Variable oder statische function zu haben, aber sie kann auch für classndefinitionen verwendet werden (und sollte in C ++ eher als static ).

Alle anonymen Namespaces in derselben Datei werden als derselbe Namespace behandelt und alle anonymen Namespaces in verschiedenen Dateien sind unterschiedlich. Ein anonymer Namespace ist äquivalent zu:

 namespace __unique_compiler_generated_identifer0x42 { ... } using namespace __unique_compiler_generated_identifer0x42; 

Das Beispiel zeigt, dass die Personen in dem Projekt, an dem Sie teilgenommen haben, keine anonymen Namespaces verstehen 🙂

 namespace { const int SIZE_OF_ARRAY_X; const int SIZE_OF_ARRAY_Y; 

Diese müssen sich nicht in einem anonymen Namespace befinden, da das const Objekt bereits über eine statische Verknüpfung verfügt und daher möglicherweise nicht mit identischen Bezeichnern in einer anderen Übersetzungseinheit in Konflikt steht.

  bool getState(userType*,otherUserType*); } 

Und das ist eigentlich eine getState() : getState() hat eine externe Verknüpfung. Es ist normalerweise besser, eine statische Verknüpfung zu bevorzugen, da dies die Symboltabelle nicht verschmutzt. Es ist besser zu schreiben

 static bool getState(/*...*/); 

Hier. Ich bin in dieselbe Falle geraten (es gibt Formulierungen im Standard, die nahelegen, dass Dateistatik für anonyme Namensräume irgendwie veraltet ist), aber wenn man in einem großen C ++ – Projekt wie KDE arbeitet, bekommt man viele Leute, die den Kopf in die richtige Richtung lenken wieder herum 🙂

Zusätzlich zu den anderen Antworten auf diese Frage kann die Verwendung eines anonymen Namespace auch die performance verbessern. Da Symbole innerhalb des Namespaces keine externe Verknüpfung benötigen, kann der Compiler den Code im Namespace aggressiver optimieren. Zum Beispiel kann eine function, die einmal in einer Schleife mehrfach aufgerufen wird, ohne Auswirkungen auf die Code-Größe eingebunden werden.

Auf meinem System benötigt der folgende Code etwa 70% der Laufzeit, wenn der anonyme Namespace verwendet wird (x86-64 gcc-4.6.3 und -O2; beachten Sie, dass der zusätzliche Code in add_val den Compiler nicht enthalten möchte) es zweimal).

 #include  namespace { double a; void b(double x) { a -= x; } void add_val(double x) { a += x; if(x==0.01) b(0); if(x==0.02) b(0.6); if(x==0.03) b(-0.1); if(x==0.04) b(0.4); } } int main() { a = 0; for(int i=0; i<1000000000; ++i) { add_val(i*1e-10); } std::cout < < a << '\n'; return 0; } 

Ein anonymer Namespace stellt die eingeschlossenen Variablen, functionen, classn usw. nur innerhalb dieser Datei zur Verfügung. In Ihrem Beispiel ist es eine Möglichkeit, globale Variablen zu vermeiden. Es gibt keine Laufzeit- oder Kompilierzeitleistungsdifferenz.

Es gibt nicht so sehr einen Vorteil oder Nachteil, abgesehen von “will ich diese Variable, function, class usw. öffentlich oder privat?”

Unbenannter Namespace begrenzt den Zugriff von class, Variable, function und Objekten auf die Datei, in der sie definiert ist. Unbenannte Namespace-functionalität ähnelt dem static Schlüsselwort in C / C ++.
static Schlüsselwort beschränkt den Zugriff der globalen Variablen und functionen auf die Datei, in der sie definiert sind.
Es gibt einen Unterschied zwischen unbenanntem Namespace und static Schlüsselwort, aufgrund dessen unbenannter Namespace gegenüber statischem Vorteil ist. static Schlüsselwort kann mit Variablen, functionen und Objekten, aber nicht mit benutzerdefinierten classn verwendet werden.
Beispielsweise:

 static int x; // Correct 

Aber,

 static class xyz {/*Body of class*/} //Wrong static structure {/*Body of structure*/} //Wrong 

Das Gleiche kann jedoch auch mit unbenanntem Namespace möglich sein. Beispielsweise,

  namespace { class xyz {/*Body of class*/} static structure {/*Body of structure*/} } //Correct