Eine Funktion von C ++ ist die Möglichkeit, unbenannte (anonyme) Namespaces wie folgt zu erstellen:
namespace {
int cannotAccessOutsideThisFile() { ... }
} // namespace
Sie würden denken, dass eine solche Funktion nutzlos wäre - da Sie den Namen des Namespace nicht angeben können, ist es unmöglich, von außen auf etwas darin zuzugreifen. Auf diese unbenannten Namespaces kann jedoch in der Datei zugegriffen werden, in der sie erstellt wurden, als hätten Sie eine implizite using-Klausel.
Meine Frage ist, warum oder wann dies der Verwendung statischer Funktionen vorzuziehen ist. Oder sind es im Wesentlichen zwei Möglichkeiten, genau dasselbe zu tun?
c++
namespaces
Head Geek
quelle
quelle
static
in diesem Zusammenhang nicht veraltet . Obwohl ein unbenannter Namespace eine überlegene Alternative zu darstelltstatic
, gibt es Fälle, in denen er beistatic
der Rettung fehlschlägt .Antworten:
Der C ++ Standard liest in Abschnitt 7.3.1.1 Unbenannte Namespaces, Absatz 2:Statisch gilt nur für Namen von Objekten, Funktionen und anonymen Vereinigungen, nicht für Typdeklarationen.
Bearbeiten:
Die Entscheidung, diese Verwendung des statischen Schlüsselworts zu verwerfen (die Sichtbarkeit einer Variablendeklaration in einer Übersetzungseinheit zu beeinflussen), wurde rückgängig gemacht ( ref ). In diesem Fall sind die Verwendung eines statischen oder eines unbenannten Namespace im Wesentlichen zwei Möglichkeiten, genau dasselbe zu tun. Weitere Informationen finden Sie in dieser SO-Frage.
Unbenannte Namespaces bieten weiterhin den Vorteil, dass Sie lokale Typen für Übersetzungseinheiten definieren können. Bitte lesen Sie diese SO-Frage für weitere Details.
Dank geht an Mike Percy , der mich darauf aufmerksam gemacht hat.
quelle
namespace
s implizit eine interne Verknüpfung, daher sollte es keinen Unterschied geben. Alle Probleme, die zuvor möglicherweise aufgrund einer schlechten Formulierung aufgetreten sind, wurden behoben, indem dies in C ++ 11 als Anforderung festgelegt wurde.Durch das Einfügen von Methoden in einen anonymen Namespace wird verhindert, dass Sie versehentlich gegen die One Definition-Regel verstoßen. So können Sie sich niemals Gedanken darüber machen, wie Sie Ihre Hilfsmethoden wie andere Methoden benennen, mit denen Sie möglicherweise verknüpfen.
Und wie von Luke hervorgehoben, werden anonyme Namespaces vom Standard gegenüber statischen Elementen bevorzugt.
quelle
Es gibt einen Randfall, in dem Statik einen überraschenden Effekt hat (zumindest für mich). Der C ++ 03-Standard besagt in 14.6.4.2/1:
Der folgende Code wird aufgerufen
foo(void*)
und nichtfoo(S const &)
wie erwartet.An sich ist dies wahrscheinlich keine so große Sache, aber es zeigt, dass für einen vollständig kompatiblen C ++ - Compiler (dh einen mit Unterstützung für
export
) dasstatic
Schlüsselwort weiterhin Funktionen bietet, die auf keine andere Weise verfügbar sind.Die einzige Möglichkeit, um sicherzustellen, dass die Funktion in unserem unbenannten Namespace nicht in Vorlagen mit ADL gefunden wird, besteht darin, sie zu erstellen
static
.Update für Modern C ++
Ab C ++ '11 haben Mitglieder eines unbenannten Namespace implizit eine interne Verknüpfung (3.5 / 4):
Gleichzeitig wurde 14.6.4.2/1 aktualisiert, um die Erwähnung der Verknüpfung zu entfernen (dies stammt aus C ++ '14):
Das Ergebnis ist, dass dieser besondere Unterschied zwischen statischen und unbenannten Namespace-Mitgliedern nicht mehr besteht.
quelle
NS::S
zu arbeiten,S
müssen Sie nicht drinnen seinnamespace {}
?Ich habe kürzlich begonnen, statische Schlüsselwörter durch anonyme Namespaces in meinem Code zu ersetzen, stieß jedoch sofort auf ein Problem, bei dem die Variablen im Namespace in meinem Debugger nicht mehr zur Überprüfung verfügbar waren. Ich habe VC60 verwendet, daher weiß ich nicht, ob dies bei anderen Debuggern kein Problem darstellt. Meine Problemumgehung bestand darin, einen 'Modul'-Namespace zu definieren, in dem ich ihm den Namen meiner CPP-Datei gab.
In meiner Datei XmlUtil.cpp definiere ich beispielsweise einen Namespace
XmlUtil_I { ... }
für alle meine Modulvariablen und -funktionen. Auf diese Weise kann ich dieXmlUtil_I::
Qualifikation im Debugger anwenden, um auf die Variablen zuzugreifen. In diesem Fall_I
unterscheidet sich das von einem öffentlichen Namespace, wieXmlUtil
ich ihn möglicherweise an anderer Stelle verwenden möchte.Ich nehme an, ein möglicher Nachteil dieses Ansatzes im Vergleich zu einem wirklich anonymen Ansatz besteht darin, dass jemand den gewünschten statischen Bereich verletzen könnte, indem er das Namespace-Qualifikationsmerkmal in anderen Modulen verwendet. Ich weiß jedoch nicht, ob das ein großes Problem ist.
quelle
#if DEBUG namespace BlahBlah_private { #else namespace { #endif
, so dass der "Modul-Namespace" nur in Debug-Builds vorhanden ist und ansonsten ein echter anonymer Namespace verwendet wird. Es wäre schön, wenn Debugger eine gute Möglichkeit hätten, damit umzugehen. Doxygen wird auch dadurch verwirrt.Die Verwendung des statischen Schlüsselworts für diesen Zweck wird vom C ++ 98-Standard nicht mehr empfohlen. Das Problem mit static ist, dass es nicht für die Typdefinition gilt. Es ist auch ein überladenes Schlüsselwort, das in verschiedenen Kontexten auf unterschiedliche Weise verwendet wird, sodass unbenannte Namespaces die Dinge ein wenig vereinfachen.
quelle
Aus Erfahrung werde ich nur bemerken, dass ältere Compiler manchmal Probleme damit haben können, obwohl dies die C ++ - Methode ist, ehemals statische Funktionen in den anonymen Namespace zu integrieren. Ich arbeite derzeit mit einigen Compilern für unsere Zielplattformen, und der modernere Linux-Compiler kann Funktionen problemlos in den anonymen Namespace einfügen.
Ein älterer Compiler, der unter Solaris ausgeführt wird und mit dem wir bis zu einer nicht spezifizierten zukünftigen Version verheiratet sind, akzeptiert ihn jedoch manchmal und kennzeichnet ihn manchmal als Fehler. Der Fehler ist nicht das, was mich beunruhigt, sondern das, was er tun könnte , wenn er ihn akzeptiert . Bis wir auf der ganzen Linie modern werden, verwenden wir immer noch statische (normalerweise klassenbezogene) Funktionen, bei denen wir den anonymen Namespace bevorzugen würden.
quelle
Wenn Sie ein statisches Schlüsselwort für eine Variable wie das folgende verwenden:
Es würde nicht in der Zuordnungsdatei angezeigt werden
quelle
Ein compilerspezifischer Unterschied zwischen anonymen Namespaces und statischen Funktionen ist beim Kompilieren des folgenden Codes zu erkennen.
Das Kompilieren dieses Codes mit VS 2017 (Angabe des Warnflags der Stufe 4 / W4 zum Aktivieren der Warnung C4505: Die nicht referenzierte lokale Funktion wurde entfernt ) und gcc 4.9 mit dem Flag -Wunused-function oder -Wall zeigen, dass VS 2017 nur eine Warnung für erzeugt die unbenutzte statische Funktion. gcc 4.9 und höher sowie clang 3.3 und höher erzeugen Warnungen für die nicht referenzierte Funktion im Namespace und eine Warnung für die nicht verwendete statische Funktion.
Live-Demo von gcc 4.9 und MSVC 2017
quelle
Persönlich bevorzuge ich statische Funktionen aus folgenden Gründen gegenüber namenlosen Namespaces:
Allein aus der Funktionsdefinition geht hervor, dass es für die Übersetzungseinheit, in der es kompiliert wird, privat ist. Bei namenlosen Namespace müssen Sie möglicherweise scrollen und suchen, um festzustellen, ob sich eine Funktion in einem Namespace befindet.
Funktionen in Namespaces werden von einigen (älteren) Compilern möglicherweise als extern behandelt. In VS2017 sind sie noch extern. Aus diesem Grund möchten Sie eine Funktion möglicherweise auch dann als statisch markieren, wenn sie sich im namenlosen Namespace befindet.
Statische Funktionen verhalten sich in C oder C ++ sehr ähnlich, während namenlose Namespaces offensichtlich nur C ++ sind. namenlose Namespaces fügen auch zusätzliche Einrückungsstufen hinzu und das gefällt mir nicht :)
Ich bin also froh zu sehen, dass die Verwendung von Static für Funktionen nicht mehr veraltet ist .
quelle
static
Schlüsselwort wendet tatsächlich eine lokale Verknüpfung auf eine Funktion an. Auch würde sicherlich nur ein begeisterter Wahnsinniger tatsächlich Einrückungen für Namespaces hinzufügen?Nachdem ich gerade erst beim Lesen Ihrer Frage von dieser Funktion erfahren habe, kann ich nur spekulieren. Dies scheint mehrere Vorteile gegenüber einer statischen Variablen auf Dateiebene zu bieten:
Ich würde gerne erfahren, ob jemand anonyme Namespaces in echtem Code verwendet hat.
quelle
Der Unterschied ist der Name des verstümmelten Bezeichners (
_ZN12_GLOBAL__N_11bE
vs_ZL1b
, was nicht wirklich wichtig ist, aber beide werden zu lokalen Symbolen in der Symboltabelle zusammengesetzt (Fehlen einer.global
asm-Direktive).Wie für einen verschachtelten anonymen Namespace:
Alle anonymen Namespaces der ersten Ebene in der Übersetzungseinheit werden miteinander kombiniert. Alle verschachtelten anonymen Namespaces der zweiten Ebene in der Übersetzungseinheit werden miteinander kombiniert
Sie können auch einen verschachtelten (Inline-) Namespace in einem anonymen Namespace haben
Sie können auch anonyme Inline-Namespaces verwenden, aber soweit ich das beurteilen kann, hat
inline
ein anonymer Namespace den Effekt 0_ZL1b
:_Z
bedeutet, dass dies eine verstümmelte Kennung ist.L
bedeutet, es ist ein lokales Symbol durchstatic
.1
ist die Länge des Bezeichnersb
und dann des Bezeichnersb
_ZN12_GLOBAL__N_11aE
_Z
bedeutet, dass dies eine verstümmelte Kennung ist.N
Dies bedeutet, dass dies ein Namespace12
ist. Dies ist die Länge des anonymen Namespace-Namens_GLOBAL__N_1
, dann der anonyme Namespace-Name_GLOBAL__N_1
, dann1
die Länge des Bezeichnersa
,a
der Bezeichnera
undE
schließt den Bezeichner, der sich in einem Namespace befindet._ZN12_GLOBAL__N_11A1aE
ist das gleiche wie oben, außer dass es eine andere Namespace-Ebene gibt1A
quelle