Frage zur One Definition Rule
-
Der Includeguard verhindert lediglich, dass Du den Header mehrmals in einer Quelldatei inkludierst.
Und "Inklusion" ist reine Textersetzung. Der Präprozessor setzt den Inhalt der Datei an der Stelle der Include-Anweisung ein. Auch in mehreren voneinander unabhängigen Quelldateien

-
Ja schon klar wie include funktioniert, nur frage ich mir nach wie vor, wie man auf die Idee kommt in der Headerdatei eine Funktion/Klasse zu definieren, außer die Funktion ist inline?
Die One Definitions Rule gilt also auch für Konstanten, man soll also auch diese auch erst in der Sourcedatei definieren, Bsp. HALF_PI? Dann hätte man aber in mehreren Dateien einen Definition und nicht nur in einer Hederdatei. Auf der anderen Seite hat man nur eine Definition, die aber von jeder Einheit inkludiert wird. *grübel
-
foo.cpp
int foo;foo.h
#ifndef FOO_H_INCLUDED #define FOO_H_INCLUDED FOO_H_INCLUDED extern int foo; #endif /* FOO_H_INCLUDED */main.cpp
#include "foo.h" int main() { foo = 42; }?
-
Swordfish schrieb:
...
Das Dateimodell von C++ ist so eine Scheiße.

Warum wurden Module aus C++11 rausgenommen? Ich schätze mal Templates machen wieder Schwierigkeiten, würde aber gern mal was dazu lesen.
-
Lichtweite schrieb:
Ja schon klar wie include funktioniert, nur frage ich mir nach wie vor, wie man auf die Idee kommt in der Headerdatei eine Funktion/Klasse zu definieren, außer die Funktion ist inline?
Wenn man auf die Idee kommt, verletzt man die ODR

Die One Definitions Rule gilt also auch für Konstanten, man soll also auch diese auch erst in der Sourcedatei definieren, Bsp. HALF_PI?
Nein, Konstanten kannst Du auch im Header definieren. Das im Beispiel war allerdings keine Konstante (trotz des Namens). Es sollte lediglich zeigen, wie man die ODR verletzen kann, wenn man an dieser Stelle "static const" vergisst.
-
Ok dann bin ich noch nicht in die Verlegenheit gekommen die Regel zu verletzten, ohne zu wissen dass es sie überhaupt gibt.

-
Ach du kannst die ODR auch verletzen ohne es zu merken.
Wird z.B. lustig wenn man inline Funktionen oder Templates verwendet, und dann z.B. darin verwendete Funktionen unterschiedlich aufgelöst werden, je nachdem welche Header davor inkuldiert wurden.
Beispiel:Translation Unit A
// in irgend einer Header definiert void foo(...); // in "Bar.h" inline void bar() { int i; foo(i); }Translation Unit B
// in irgend einer anderen Header definiert void foo(int i); // in "Bar.h" inline void bar() { int i; foo(i); }Und schon haben wir die ODR verletzt, bekommen aber üblicherweise keine Diagnostic (Fehlermeldung/Warning). Dafür aber ein schönes Ratespiel was nun wirklich passieren wird und im Falle des Falles viele lustige Stunden der Fehlersuche.
-
Das ergibt dann das undefinierte Verhalten, richtig? Aber wie kommt es zu so einer Konstellation? Wieso sollte ich bei inline Funktionen Deklaration und Definition in getrennten Dateien halten? Immer wenn ich denke, ich habe es verstanden, ergeben sich neue Fragen

-
Lichtweite schrieb:
Das ergibt dann das undefinierte Verhalten, richtig? Aber wie kommt es zu so einer Konstellation? Wieso sollte ich bei inline Funktionen Deklaration und Definition in getrennten Dateien halten?
Solltst du nicht, aber wie hustbaer gezeigt hat ist die Definition immer kontextabhängig, d.h. die Definition im Header kann von ÜE zu ÜE in unterschiedlichen Kontexten stehen und deshalb nur syntaktisch identisch sein, semantisch aber nicht.
-
hustbaer schrieb:
Beispiel
Aus diesem Grund packt man immer alles, was nicht in einem Header deklariert wurde, in einen anonymen Namensraum rein:
namespace { ... }
-
Lichtweite schrieb:
Die One Definitions Rule gilt also auch für Konstanten, man soll also auch diese auch erst in der Sourcedatei definieren, Bsp. HALF_PI? Dann hätte man aber in mehreren Dateien einen Definition und nicht nur in einer Hederdatei. Auf der anderen Seite hat man nur eine Definition, die aber von jeder Einheit inkludiert wird. *grübel
Kleiner Hinweis: Globale Konstanten haben internal linkage, dh:
// a.h int pi = 3; // main.cc #include "a.h" // a.cc #include "a.h" g++ a.cc main.cc ... :warning: autsch linker meckert weil er zwei definitionen von pi in zwei objekt dateien hat.// a.h const int pi = 3; // nun const -> internal linkage. name wird nicht nach außen freigegeben // main.cc #include "a.h" // a.cc #include "a.h" g++ a.cc main.cc ... funktioniert!
-
anonymespace schrieb:
hustbaer schrieb:
Beispiel
Aus diesem Grund packt man immer alles, was nicht in einem Header deklariert wurde, in einen anonymen Namensraum rein:
namespace { ... }Du hast nicht verstanden worum es geht.
Die drei Funktionen "foo(...)", "foo(int)" und "bar()" sind alle drei in Headers definiert.