Inline
-
Compiler haben da ja recht viel Optimierungsmöglichkeiten und können ganze Funktionen wegoptimieren. Ansonsten sehe ich da im Standard nichts, was es einer Implementierun verbietet selber zu inlinen, oder noch weiter zu gehen. (Solange es keinen Unterschied bei der Ausführung macht).
Export ist dazu gedacht eine Templatedefinition in einer Übersetzungseinheit zu binden und die Mehrfachdefinition zu verhindern. Was ja bekannterweise nur sehr wenige Compiler unterstützen. (Comeau, der einzige, den ich kenne).
-
Danke für die Antworten.
Also braucht man das Schlüsselwort
inlineeigentlich nicht selber, weil man sich auf eine Optimierung durch den Compiler verlassen kann?Badestrand schrieb:
Btw: Der Compiler muss da nichts "in Dateien verschieben", sowas passiert ja auf Symbol-Ebene und wird vom Optimierer übernommen.
Nehmen wir an, wir hätten eine selbst definierte Inline-Funktion in einem Header. Dem Compiler ist die Funktion zu gross, er optimiert das
inlineweg. Die Funktion darf also in diesem Header nur noch deklariert werden. Spielt es dann keine Rolle, wo sie definiert ist (das ist in gar keiner Datei mehr, sondern direkt ein Symbol)? Es wird also automatisch Speicherplatz bereitgestellt?drakon schrieb:
Export ist dazu gedacht eine Templatedefinition in einer Übersetzungseinheit zu binden und die Mehrfachdefinition zu verhindern. Was ja bekannterweise nur sehr wenige Compiler unterstützen. (Comeau, der einzige, den ich kenne).
Okay, ich hab mich jetzt noch einmal ein bisschen genauer dazu informiert (z.B. auch den Artikel über Templates gelesen). Es ist also kaum möglich, Templates in Header- und Implementierungsdatei zu trennen.
Das heisst, normalerweise werden Templates mehrfach definiert? Kann das nicht zu Problemen führen?
-
Nexus schrieb:
Dem Compiler ist die Funktion zu gross, er optimiert das
inlineweg. Die Funktion darf also in diesem Header nur noch deklariert werden.Was soll das heißen, dass das inline wegoptimiert wird? Jedenfalls hängt die Frage, wo Funktionen definiert werden müssen (mithin: ob ein Programm standardkonform ist oder nicht), nicht von den Launen des Compilers ab.
Nexus schrieb:
Das heisst, normalerweise werden Templates mehrfach definiert? Kann das nicht zu Problemen führen?
Dann, wenn die Templatedefinition in den verschiedenen ÜEs nicht exakt gleich sind (dieses "exakt gleich" bedarf einer relativ umfangreichen Definition). In diesem Fall ist die ODR verletzt. Sind die Definitionen alle exakt gleich, kann der Compiler/Linker sich irgendeine davon heraussuchen. Praktisch heißt das, dass bei der Instantiierung von Templates aus Sicht des Linkers sogenannte "weak symbols" exportiert werden, solche Symbole dürfen mehrfach (in verschiedenen Objektdateien) existieren, und der Linker nimmt dann bei der Erstellung des fertigen Programmes irgendein beliebiges (für gewöhnlich, das erste, das gefunden wird).
-
camper schrieb:
Nexus schrieb:
Dem Compiler ist die Funktion zu gross, er optimiert das
inlineweg. Die Funktion darf also in diesem Header nur noch deklariert werden.Was soll das heißen, dass das inline wegoptimiert wird? Jedenfalls hängt die Frage, wo Funktionen definiert werden müssen (mithin: ob ein Programm standardkonform ist oder nicht), nicht von den Launen des Compilers ab.
Ich meinte mit wegoptimieren, dass eine Inline-Funktion vom Compiler zu einer normalen gemacht wird, wenn sich das
inlinesich mehr lohnt (bei grossen Funktionen). Wenn eine solche Umwandlung vom Compiler stattfindet, kann man davon ausgehen, dass es aufs Gleiche rauskommt, wie wenn man die Funktion selber als nicht inline definieren würde (und umgekehrt genauso)?camper schrieb:
Nexus schrieb:
Das heisst, normalerweise werden Templates mehrfach definiert? Kann das nicht zu Problemen führen?
Dann, wenn die Templatedefinition in den verschiedenen ÜEs nicht exakt gleich sind (dieses "exakt gleich" bedarf einer relativ umfangreichen Definition). In diesem Fall ist die ODR verletzt. Sind die Definitionen alle exakt gleich, kann der Compiler/Linker sich irgendeine davon heraussuchen. Praktisch heißt das, dass bei der Instantiierung von Templates aus Sicht des Linkers sogenannte "weak symbols" exportiert werden, solche Symbole dürfen mehrfach (in verschiedenen Objektdateien) existieren, und der Linker nimmt dann bei der Erstellung des fertigen Programmes irgendein beliebiges (für gewöhnlich, das erste, das gefunden wird).
Okay, danke für die Erklärung. Ich nehme an, dass das "exakt gleich" in normalen Fällen erfüllt ist und man sich darüber keine weiteren Gedanken machen muss...
Was ich aber trotzdem nicht ganz verstehe: Wieso sind bei Templates solche Mehrfachdefinitionen erlaubt, bei anderen Sprachkonstrukten (normale Klassen, Funktionen, Variablen) aber nicht? Ist das eine Sonderregelung, weil Templates sonst nicht implementierbar wären?
-
Nexus schrieb:
Ich meinte mit wegoptimieren, dass eine Inline-Funktion vom Compiler zu einer normalen gemacht wird, wenn sich das
inlinesich mehr lohnt (bei grossen Funktionen). Wenn eine solche Umwandlung vom Compiler stattfindet, kann man davon ausgehen, dass es aufs Gleiche rauskommt, wie wenn man die Funktion selber als nicht inline definieren würde (und umgekehrt genauso)?Arbeite mit deinem Compiler zusammen. Also verlass dich nicht nur auf deinen Compiler und verlass dich nicht nur auf dich selbst.
Ich bin mir jetzt nicht sicher, aber eineinlineFunktion, darf ein Compiler nicht de'inlinen. Er darf aber umgekehrt nicht-inlinezuinlineFunktionen machen. Es wird aber nirgends vorgeschrieben, dass er dies auch macht!Nexus schrieb:
Was ich aber trotzdem nicht ganz verstehe: Wieso sind bei Templates solche Mehrfachdefinitionen erlaubt, bei anderen Sprachkonstrukten (normale Klassen, Funktionen, Variablen) aber nicht? Ist das eine Sonderregelung, weil Templates sonst nicht implementierbar wären?
Was verstehst du unter Mehrfachdefinition?
Irgendwie habe ich das Gefühl, dass du zwei Dinge nicht so ganz verstehst:
1. Der Code, welcher du schreibst, verschwindet komplett beim Compilieren und es entstehen daraus Objekt-Dateien (*.o für g++, *.obj für MSVC).
Zuerst wird der Präprozessor ausgeführt, welcher eine Kopie des Codes verändert. Danach läuft der Compiler drüber, welcher aus dieser veränderten Kopie eine Objekt-Datei erstellt. Ob zum Beispiel eine Funktion inline ist oder nicht, hängt danach nur noch von einem Flag ab (Bit gesetzt oder nicht). Von C++ Code ist da definitiv nichts mehr zu sehen und hat oft auch nichts mehr damit zu tun. Die Objekt-Dateien sind in einer eigenen Sprache geschrieben. Meistens einer so flexiblen, dass sich allerhand anderer Sprachen in diese übersetzen lassen. Aus dieser eigenen Sprache erzeugt der Compiler, bzw. Linker, die ausführbare Datei.
2. Ein Template ist nur eine Schablone. Das ist keine vollwertige Klasse! Dank der Schablone kann der Compiler dann Klassen erzeugen und mit den erzeugten Klassen dann Objekte. Die erzeugten Klassen sind dann aber sicher nicht als C++ Code vorhanden, sondern bereits auf der Symbolebene, bzw. in der Objekt-Datei. Dort gelten, wie schon bei Punkt 1 gesagt, andere Regeln.Grüssli
-
Ich bin mir jetzt nicht sicher, aber eine inline Funktion, darf ein Compiler nicht de'inlinen.
Doch. inline ist nur ein Hinweis für den Kompiler, dass er kann, wenn er es für richtig hält.
Simon
-
-
Dravere schrieb:
Ich bin mir jetzt nicht sicher, aber eine
inlineFunktion, darf ein Compiler nicht de'inlinen. Er darf aber umgekehrt nicht-inlinezuinlineFunktionen machen.Gut, dass du dir nicht ganz sicher bist. Der Compiler darf sehr wohl das inline ignorieren (manchmal kann er nicht anders, z.B. ist es manchmal nicht so einfach, Rekursionen zu inlinen). Insgesamt ist inline nur ein Hinweis an den Compiler "unter Umständen könntest du hier..." - den er befolgen kann, aber nicht muss. Die meisten modernen Compiler sind durchaus in der Lage, die inline-Entscheidung selber zu treffen, und zwar aus stichhaltigeren Gründen als der Intuition des Programmierers.
Sutter hat in Exceptional C++ Style, Item 25, 9 Seiten übers inlining geschrieben - mit dem Fazit, dass man inline nicht explizit angeben sollte, bis der Profiler einem bescheinigt dass es nötig ist. (Alles in allem ist Inlining eine Optimierung, und frühzeitige Optimierungen sind Mist).Dravere schrieb:
Nexus schrieb:
Was ich aber trotzdem nicht ganz verstehe: Wieso sind bei Templates solche Mehrfachdefinitionen erlaubt, bei anderen Sprachkonstrukten (normale Klassen, Funktionen, Variablen) aber nicht? Ist das eine Sonderregelung, weil Templates sonst nicht implementierbar wären?
Was verstehst du unter Mehrfachdefinition?
Irgendwie habe ich das Gefühl, dass du zwei Dinge nicht so ganz verstehst:
1. Der Code, welcher du schreibst, verschwindet komplett beim Compilieren und es entstehen daraus Objekt-Dateien (*.o für g++, *.obj für MSVC).
Zuerst wird der Präprozessor ausgeführt, welcher eine Kopie des Codes verändert. Danach läuft der Compiler drüber, welcher aus dieser veränderten Kopie eine Objekt-Datei erstellt. Ob zum Beispiel eine Funktion inline ist oder nicht, hängt danach nur noch von einem Flag ab (Bit gesetzt oder nicht). Von C++ Code ist da definitiv nichts mehr zu sehen und hat oft auch nichts mehr damit zu tun. Die Objekt-Dateien sind in einer eigenen Sprache geschrieben. Meistens einer so flexiblen, dass sich allerhand anderer Sprachen in diese übersetzen lassen. Aus dieser eigenen Sprache erzeugt der Compiler, bzw. Linker, die ausführbare Datei.
2. Ein Template ist nur eine Schablone. Das ist keine vollwertige Klasse! Dank der Schablone kann der Compiler dann Klassen erzeugen und mit den erzeugten Klassen dann Objekte. Die erzeugten Klassen sind dann aber sicher nicht als C++ Code vorhanden, sondern bereits auf der Symbolebene, bzw. in der Objekt-Datei. Dort gelten, wie schon bei Punkt 1 gesagt, andere Regeln.Grüssli@Nexus: im Thread "Templates!?" hab ich eine kurze Erklärung geschrieben, was der Compiler mit Templates bei ihrer Instantiierung anstellt - er erzeugt anhand der Informationen über die eingesetzten Typen und anhand der ihm vorliegenen Templatedefinition den nötigen Code. Wenn also in zwei verschiedenen Übersetzungseinheiten das gleiche (nicht zwangsläufig das selbe) template instantiiert wird, wird beidesmal der selbe (!) Objektcode erzeugt (vorausgesetzt die beiden verwendeten Templatedefinitionen sind sich hinreichend ähnlich), so dass in beiden Objektdateien die von camper angesprochenen weak symbols und der zugehörige Code vorhanden sind. Da beidemal die komplette templatedefinition mit verwurstet wird, kann (bzw. braucht) der Compiler nicht zu unterscheiden ob es sich um dieselbe Definition (also dieselbe source-Datei) oder zwei identische Definitionen (derselbe Code in zwei verschiedenen Dateien) handelt, oder ob es sogar leicht verschiedene Definitionen sind, die aber zum selben Ergebnis führen. Wenn die beiden Definitionen so verschieden sind, dass das Ergebnis sich deutlich unterscheidet, dann ist das Ergebnis meines Wissens undefiniert, da nicht festgelegt ist, welche der beiden weak symbols (mit den dranhängenden verschiedenen Codes) sich der Linker aussucht.
Was ich mir beispielsweise als akzeptablen Unterschied vorstellen könnte sind verschiedene Zugriffsspezifizierer bei Methoden - solang keiner dagegen verstößt meckert der Compiler nicht, und der Linker kriegt den Unterschied private/protected/public vermutlich sowieso nicht mit, der erzeugte Code müsste also identisch sein.
-
Nexus schrieb:
Okay, danke für die Erklärung. Ich nehme an, dass das "exakt gleich" in normalen Fällen erfüllt ist und man sich darüber keine weiteren Gedanken machen muss...
Solange du den Code nicht kopierst und veränderst, brauchst du ja immer den gleichen Header. Somit wird es schwer unterschiedlichen Code zu haben.

-
Dravere schrieb:
Was verstehst du unter Mehrfachdefinition?
Ich meinte damit Symbole, die (schlussendlich gesehen) in mehreren Objektdateien definiert wurden, sodass für den Linker das selbe Symbol mehrfach existiert. Auf Quelltextbasis passiert das ja, wenn man einen Header mit Definitionen in verschiedene CPP-Dateien einbindet.
Der Vorgang der Codeerstellung war mir schon noch ungefähr so im Kopf - aber eben ungefähr
- danke für deine Erläuterung.pumuckl schrieb:
Sutter hat [...] geschrieben - mit dem Fazit, dass man inline nicht explizit angeben sollte, bis der Profiler einem bescheinigt dass es nötig ist. (Alles in allem ist Inlining eine Optimierung, und frühzeitige Optimierungen sind Mist).
Okay, so was in der Art wollte ich hören. Ich verzichtete bisher weitgehend auf den Einsatz von
inline, in der Hoffnung, der Compiler könnte das sowieso besser entscheiden.Auch dir danke ich für die Erklärungen. Ich hab jetzt auch noch deinen Beitrag über Templates gelesen, er hat einiges geklärt.
Diese sogenannten Weak Symbols treten nur bei Templates auf? Sonstige Mehrfachdefinitionen enden ja in Linkerfehlern. Aber weil bei Templates noch kein festes Konstrukt (Funktion oder Klasse), sondern nur eine Schablone vorliegt, macht es nichts, wenn mehrere identische Symbole vorhanden sind? Oder wurde da eben eine Sonderregelung eingeführt, sodass der Linker alles mehrfach definierte ausser Templates mit Fehlermeldungen meldet?
drakon schrieb:
Solange du den Code nicht kopierst und veränderst, brauchst du ja immer den gleichen Header. Somit wird es schwer unterschiedlichen Code zu haben.

Okay

Ich frag mich, ob das in der Praxis überhaupt zu Problemen führt (gibt es viele Leute, die Header kopieren und leicht abändern)?
-
Nexus schrieb:
Aber weil bei Templates noch kein festes Konstrukt (Funktion oder Klasse), sondern nur eine Schablone vorliegt, macht es nichts, wenn mehrere identische Symbole vorhanden sind? Oder wurde da eben eine Sonderregelung eingeführt, sodass der Linker alles mehrfach definierte ausser Templates mit Fehlermeldungen meldet?
Das hast du vermutlich missverstanden. Die Symbole werden ja erst im Objektcode erzeugt, sind sozusagen die Schnittstellen der Objektdateien. Bei Templates wird Objektcode ja erst erzeugt, wenn sie instantiiert werden. Ich bin was die Symbole und das Linking angeht icht so ganz firm, aber ich denke man kann das an folgendem Beispiel verstehen:
wenn ich einen Funktionsaufruf habe, macht der Compiler daraus im Objektcode einen Aufruf an ein bestimmtes Symbol. Wenn ich die Definition einer Funktion in einer ÜE habe, wird dauraus eben so ein Symbol. So ein Symbol beinhaltet in gewisser Form den namen, Rückgabewert und parameterliste einer Funktion.
Das Problem bei Temaplate-instantiierungen ist, dass sie in mehreren ÜEs vorkommen können. Da der Compiler die komplette Templatedefinition mit dem angegebenen Typ instantiiert, kann es vorkommen, dass beispeilsweise die Funktionvoid f<int>()in mehreren Übersetzungseinheiten vorkommt. Es gibt also das Selbe Symbol in mehreren Objektdateien, wenn der Compiler fertig ist. Damit der Linker nicht anfängt zu lamentieren muss also die Übersetzung für instantiierte Template-Funktionen ein weak symbol liefern. Man könnte sich grundsätzlich also vorstellen, den Standard um ein Schlüsselwort (weak?) zu erweitern das dafür sorgt, dass damit gekennzeichnete Funktionen zu weak symbols übersetzt werden, um zu sagen "Hey Linker, kann sein dass das Symbol hier an mehreren Stellen angeboten wird, such dir einfach eins aus, wird schon passen".Die Profis bezüglich Compiler-Interna mögen mich berichtigen wenn ich hier völligen Humbug verzapft hab, bin im dragon book noch nicht so weit fortgeschritten...
-
Okay, dann ist es einfach so festgelegt, dass bei Templates Weak Symbols erstellt werden, und bei normalen Klassen/Funktionen/Variablen normale (strong?) Symbole, die nur einmal definiert sein dürfen?
-
Das Thema wäre für mich immer noch aktuell
