Warum sollten Typen in unbenannte Namespaces eingefügt werden?

8

Ich verstehe die Verwendung von unbenannten Namespaces, um Funktionen und Variablen intern zu verknüpfen. Unbenannte Namespaces werden nicht in Header-Dateien verwendet; nur Quelldateien. In einer Quelldatei deklarierte Typen können nicht außerhalb verwendet werden. Also, was bringt es, Typen in unbenannte Namespaces zu setzen?

Siehe diese Links, wo erwähnt wird, dass Typen in unbenannte Namespaces eingefügt werden können:

Francis Xavier 19.08.2015, 17:58
quelle

3 Antworten

13

Wo möchten Sie andere lokale Typen als den unbenannten Namespace einfügen? Typen können keinen Verknüpfungsbezeichner wie static haben. Wenn sie nicht öffentlich bekannt sind, z. B. weil sie in einem Header deklariert sind, besteht eine gute Chance, dass Namen von lokalen Typen in Konflikt geraten, z. B. wenn zwei Übersetzungseinheiten Typen mit dem gleichen Namen definieren. In diesem Fall würden Sie mit einer ODR-Verletzung enden. Das Definieren der Typen in einem unbenannten Namespace beseitigt diese Möglichkeit.

Um ein bisschen konkreter zu sein. Überlegen Sie, Sie haben

%Vor%

Wenn Sie diese drei Übersetzungseinheiten verknüpfen, stimmen die Definitionen von helper von foo.cpp und bar.cpp nicht überein. Der Compiler / Linker muss diese nicht erkennen, aber jeder Typ, der im Programm verwendet wird, muss eine konsistente Definition haben. Ein Verstoß gegen diese Einschränkungen wird als Verletzung der "One-Definition-Regel" (ODR) bezeichnet. Jede Verletzung der ODR-Regel führt zu undefiniertem Verhalten.

Angesichts des Kommentars scheint es ein wenig überzeugender zu sein. Der relevante Abschnitt der Norm ist 3.2 [basic.defodr] Absatz 6:

  

Es kann mehr als eine Definition eines Klassentyps (Abschnitt 9), Aufzählungstyp (7.2), Inline-Funktion mit externer Verknüpfung (7.1.2), Klassenvorlage (Abschnitt 14), nicht statische Funktionsvorlage (14.5.) geben .6), statisches Datenelement   einer Klassenvorlage (14.5.1.3), einer Elementfunktion einer Klassenvorlage (14.5.1.1) oder einer Vorlagenspezialisierung, für die einige Vorlagenparameter nicht angegeben sind (14.7, 14.5.5) in einem Programm, sofern jede Definition in a erscheint verschiedene Übersetzungseinheiten und sofern die Definitionen die folgenden Anforderungen erfüllen. Wenn eine solche Entität mit dem Namen D in mehr als einer Übersetzungseinheit definiert ist, dann muss jede Definition von D aus der gleichen Tokenfolge bestehen; und   [...]

Es gibt viele weitere Einschränkungen, aber "besteht aus der gleichen Folge von Token" ist eindeutig ausreichend, um z.B. die Definitionen in der obigen Demo von legal.

    
Dietmar Kühl 19.08.2015, 18:05
quelle
4
  

Was bringt es also, Typen in unbenannte Namespaces einzufügen?

Sie können kurze, aussagekräftige Klassen mit Namen erstellen, die möglicherweise in mehreren Dateien ohne das Problem von Namenskonflikten verwendet werden.

Zum Beispiel verwende ich zwei Klassen oft in unbenannten Namensräumen - Initializer und Helper .

%Vor%

Ich kann dieses Code-Muster in so vielen Dateien wiederholen, wie ich möchte, ohne dass die Namen Initializer und Helper in die Quere kommen.

Aktualisierung, als Antwort auf einen Kommentar von OP

file-1.cpp:

%Vor%

file-2.cpp:

%Vor%

Befehl zum Erstellen:

%Vor%

Ich bekomme Linker Fehlermeldung über mehrere Definitionen von Initializer::Initializer() . Bitte beachten Sie, dass der Link den Linker nicht benötigt, um diesen Fehler zu erzeugen. Aus Abschnitt 3.2 / 4:

  

Jedes Programm soll genau eine Definition jeder nicht-inline Funktion oder Variable enthalten, die in diesem Programm verwendet wird; keine Diagnose erforderlich.

Der Linker erzeugt keinen Fehler, wenn die Funktionen inline definiert sind:

%Vor%

Das ist in einem einfachen Fall in Ordnung, da die Implementierungen identisch sind. Wenn die Inline-Implementierungen unterschiedlich sind, unterliegt das Programm einem nicht definierten Verhalten.

    
R Sahu 19.08.2015 18:09
quelle
0

Ich könnte etwas spät dran sein, um die Frage zu beantworten, die das OP gemacht hat, aber da ich denke, dass die Antwort nicht ganz klar ist, möchte ich zukünftigen Lesern helfen.

Lass uns einen Test machen ... kompiliere die folgenden Dateien:

%Vor% %Vor% %Vor%

Führen Sie nun die ausführbare Datei aus. Sie würden erwarten zu sehen:

%Vor%

Was Sie sehen sollten, ist:

%Vor%

Was ist passiert?!? !!

Versuchen Sie nun, einen unbenannten Namensraum um die "Test" -Klasse in "test.cpp" zu legen:

%Vor%

Kompiliere es erneut und starte es. Die Ausgabe sollte sein:

%Vor%

Wow! Es funktioniert!

Wie sich herausstellt, ist es wichtig Klassen in unbenannten Namespaces zu definieren, damit Sie die richtige Funktionalität daraus erhalten, wenn zwei Klassennamen in verschiedenen Übersetzungseinheiten identisch sind. Nun zu warum das ist der Fall, ich habe keine Nachforschungen darüber angestellt (vielleicht könnte hier jemand helfen?) Und deshalb kann ich es dir nicht wirklich sagen. Ich antworte rein von einem praktischen Standpunkt.

Was ich allerdings vermuten würde ist, dass C-Strukturen, obwohl sie true sind, in der Tat für eine Übersetzungseinheit lokal sind. Sie unterscheiden sich ein wenig von Klassen, da Klassen in C ++ normalerweise ihnen zugeordnet sind . Verhalten bedeutet Funktionen und Funktionen sind, wie wir wissen, nicht lokal für die Übersetzungseinheit.

Das ist nur meine Annahme.

    
Michail Angelos 26.09.2017 08:42
quelle

Tags und Links