namespace Problem
-
RHBaum schrieb:
und warum sollt ich funktionen, die ich getrennt deklariere und definiere ned inlinen koennen ?
wie sollte der compiler denn den code der inline-funktion inline einfügen, wenn er die definition der funktion nicht hat?
inline kannst du verwenden, um die ODR zu umgehen, indem du inline-funktionen außerhalb der klassendefinition, aber noch *im header* definierst. das würde ohne inline nicht funktionieren. btw. ob der code tatsächlich geinlined wird, ist sowieso niemals deine entscheidung.
-
ob der code tatsächlich geinlined wird, ist sowieso niemals deine entscheidung.
Ob tatsaechlich geinlined wird, ist klar, das entscheidet der compiler selber ...
wenn er die definition der funktion nicht hat?
Die hat er doch, nur ned halt gleich in der h datei zur verfuegung.
Klar ist es etwas aufwendiger, aber koennen sollt es der compiler scho ...
Weiss ned was der gcc macht ....
aber der VS 2005 compiler z.b. mault bei einem
class X
{
static inline void foo();
}wenn die definition von foo fehlt, kein "unresolved symbol" an, wie bei normalen Fehlern dieser art, sondern hat ne eigene Fehlermeldung ala "could not found definition of inline function" ... also geh ich davon aus dass er da scho versucht zu inlinen, und ned einfach ne normale funktion drauss macht, nur weils ned gleich im header implementiert wurde ...
genau so wie er fehler generiert wenn man die adresse von dem ding bekommen will ... egal ob das dann noch im header oder ned implementiert wurde.
Aber ob ers wirklich und letztendlich inlinet ... keine ahnung, kriegt man das irgendwie raus ?
Hab keine Ahnung wie der compiler es das wirklich dann handhabt, wenn er das inline gleich beim compilieren aufloesen will, klar, dann braucht er das im header.
Aber kann er ned beim linken inlines ned auch aufloesen, dort hat er doch dann alle Bloecke.Ich hab mal gelernt, das man inline rein als Hinweis an den compiler verwenden soll, das man mit der funktion nix anstellt, was ein "inline" vermeiden koennte, also funktionspointer ziehen, oder es polymorph zu verwenden, oder recursiv ... egal wie und wo man es definiert. Und das grad deshalb der compiler auch keine Fehler generiert, wenn er es nicht kann (das war aber noch vor 95) ...
Genau so schreibt der c++ standard auch ned vor, das eine nicht im header implementierte funktion nicht geinlinet werden darf.
Momentan iss inline vielleicht an paar Stellen einfach "sinnlos" ... aber kann man das fuer jeden compiler und fuer die naechsten Jahre im vorraus sagen ?Ciao ...
-
RHBaum schrieb:
ob der code tatsächlich geinlined wird, ist sowieso niemals deine entscheidung.
Ob tatsaechlich geinlined wird, ist klar, das entscheidet der compiler selber ...
wenn er die definition der funktion nicht hat?
Die hat er doch, nur ned halt gleich in der h datei zur verfuegung.
in der regel wird er sie nicht haben. der compiler übersetzt nur jeweils eine einzelne übersetzungseinheit (sprich "cpp-datei") und sieht daher auch nur alle definitionen innerhalb dieser datei. um auf entitäten außerhalb dieser übersetzungseinheit zugriff zu bekommen, muss man diese deklarieren. insgesamt - also in allen übersetzungseinheiten - darf eine entität allerdings nur einmal vorkommen. (und dann gibt es noch einen haufen ausnahmen von dieser regel)
also wenn das jemand können sollte, dann ein linker, weil nur der zugriff auf alle übersetzungseinheiten hat. und ja, das wäre in der tat sehr aufwändig.class X { static inline void foo(); } wenn die definition von foo fehlt, kein "unresolved symbol" an, wie bei normalen Fehlern dieser art, sondern hat ne eigene Fehlermeldung ala "could not found definition of inline function" ... also geh ich davon aus dass er da scho versucht zu inlinen, und ned einfach ne normale funktion drauss macht, nur weils ned gleich im header implementiert wurde ...siehe campers post.
-
queer_boy schrieb:
also wenn das jemand können sollte, dann ein linker, weil nur der zugriff auf alle übersetzungseinheiten hat. und ja, das wäre in der tat sehr aufwändig.
Aber nicht unmöglich, schließlich gibt es populäre Implementierungen, die sog. Link-Time Code Generation beherrschen und auch durchführen. Der Microsoft-Compiler hat mich da schon mehrmals "verarscht", weil ich wollte dass eine Funktion nicht geinlined wird.
Siehe hierzu auch "25. Inline Redux" aus Sutters Exceptional C++ Style.
-
inline kannst du verwenden, um die ODR zu umgehen, indem du inline-funktionen außerhalb der klassendefinition, aber noch *im header* definierst.
Steh ich auch noch bissi aufm schlauch ...
class X { public: void foo(); }; void X::foo() { // dosomething }Klar, das in einem header, und den header in 2 unterschliedlichen linker einheiten, gibt doppelte symbole wenn man beide einheiten zusammenlinkt.
Iss aber auch konequent, weil konstanten und variablen kann ich so auch ned definieren. und bei denen hilft mir dann nen inline nicht, also muss ich umbauen ! (ok, variablen und konstanten inlinen zu wollen macht auch ned viel sinn ^^ )Aber was ist der vorteil gegenueber
class X { public: void foo() { // dosomething } };Das einzige wo ich die erstere Version verwende, ist eher bei templates, und da treten das problem ned auf.
Also waer inline als solches wirklich sinnlos, wenn man rein technisch rangeht. weil inlinen tut der compiler soweiso selber, oder auch nicht, und brauchen tut man es (fast) nie.
Ich seh es halt wie ne selbstauferlegung, genau wie bei const z.b.
Es gibt definitiv stellen, wo ein const zu keiner optimierung fuehrt, weil der compiler da selber erkennt, ob er optimieren kann oder nicht.
Aber soll man deswegen das const weglassen ? Oftmals hats halt einfach nur informativen character.
inline heisst fuer mich, das ist ne kleine knackige funktion, die der compiler so schnell ausfuehren soll wie er kann. Das ding ist weder rekursiv, noch sollt ich nen funktionspointer von ziehen ....Ciao ...
-
Const hat nicht nur informativen Charakter - const erlaubt dem Compiler, gewisse Sachen ggü. dem Programmierer durchzusetzen. Das hat nichts mit Optimierungen zu tun, sondern mit der Einhaltung von Verträgen.
Inline dagegen ist, wie Du schon festgestellt hast, oft überflüssig, oder "in many respects semantically equivalent to whitespace", wie Sutter in dem vorhin erwähnten Buch selbst auch schreibt. "In many respects" eben, weil es diesen einen Fall gibt (dein Beispiel), wo man inline zur Umgehung der ODR braucht, was mit dem Inlining an sich garnicht mehr viel zu tun hat.
-
RHBaum schrieb:
inline kannst du verwenden, um die ODR zu umgehen, indem du inline-funktionen außerhalb der klassendefinition, aber noch *im header* definierst.
Steh ich auch noch bissi aufm schlauch ...
auf den punkt gebracht: inline-funktionsdefinitionen im header sind erlaubt *obwohl* sie external linkage haben.
//header.h //entweder class X { public: void foo(); }; inline void X::foo() { // dosomething } //oder class X { public: inline void foo(); }; void X::foo() { // dosomething }LordJaxom schrieb:
Aber nicht unmöglich, schließlich gibt es populäre Implementierungen, die sog. Link-Time Code Generation beherrschen und auch durchführen. Der Microsoft-Compiler hat mich da schon mehrmals "verarscht", weil ich wollte dass eine Funktion nicht geinlined wird.
was nichts daran ändert, dass die definition einer als inline deklarierten funktion in jeder übersetzungseinheit vorhanden sein *muss*. dieses problem gibt es also nicht.
-
Meines Wissens besagt die ODR nicht, dass es keine Mehrfachdefinitionen derselben Funktion oder Klasse geben darf. Sie besagt lediglich, dass alle Definitionen einer Funktion/Klasse identisch sein muessen.
-
3.2 - One Definition Rule
1 No translation unit shall contain more than one definition of any variable, function, class type, enumeration type or template.
was du meinst gehört auch dazu:
5 There can be more than one definition of a class type (clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template clause 14), non-static function template (14.5.5), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template special ization for which some template parameters are not specified (14.7, 14.5.4) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements.
[...]
- each definition of D shall consist of the same sequence of tokens
[...]
-
Const hat nicht nur informativen Charakter - const erlaubt dem Compiler, gewisse Sachen ggü. dem Programmierer durchzusetzen. Das hat nichts mit Optimierungen zu tun, sondern mit der Einhaltung von Verträgen.
ist doch bei inline fast genau so ...
virtual inline, oder inline virtual mosert mein compiler zumindest an ^^
genau so wie er es ned mag, wenn ich von ner inline funktion nen pointer ziehen will.
Ok, const vielleicht bissi doof gewaehlt, weil ich mit const die restriktion and die benutzer meiner Bib weitergeben kann ...
Obwohl, wenn nen anderer Programmierer ne funktion als inline sieht, dann sollt es ihn auch irgendwie davon abhalten, nen funktionspointer zu ziehen.Ciao ...
-
Ok, hab noch mal beim Stroustroup nachgeschaut ... der MS compiler verhaelt sich da ned 100% Standard konform.
Stroustrup meint, das man von einer funktion und deren Variablen immer auch die Adressen abfragen koennen muss,
Zitat: die Semantik einer Funktion aendert sich durch das inline nicht.Damit ist das inline wirklich ueberfluessig .... weil danach nen inline virtual keinen error liefern duerfte ... sondern das inline simpel einfach nur ausgehebelt wird.
Meines Wissens besagt die ODR nicht, dass es keine Mehrfachdefinitionen derselben Funktion oder Klasse geben darf. Sie besagt lediglich, dass alle Definitionen einer Funktion/Klasse identisch sein muessen.
Nein, die ODR sagt das nur eine Definition vorhanden sein darf !
Das inline weicht die funktion genau dahingehend auf, das es zwar mehrere definitionen geben darf, die aber die Semantik ueberall gleich sein muss.
Also inline entbindet eine funktion von der ODR ...Ciao ...
-
RHBaum schrieb:
Const hat nicht nur informativen Charakter - const erlaubt dem Compiler, gewisse Sachen ggü. dem Programmierer durchzusetzen. Das hat nichts mit Optimierungen zu tun, sondern mit der Einhaltung von Verträgen.
ist doch bei inline fast genau so ...
virtual inline, oder inline virtual mosert mein compiler zumindest an ^^
genau so wie er es ned mag, wenn ich von ner inline funktion nen pointer ziehen will.dann solltest du dir einen compiler besorgen, der das alles kann, das sollte nämlich kein problem sein.
class Foo { public: virtual ~Foo () {} //no problem }; inline void foo () {} int main () { void (*ptr) () = foo; //no problem }
-
Hab weiter Probleme, also ich hab das "extern" Objekt im Header deklariert, weil in der .cpp wars ja falsch, weil man da definiert!
Wenn ich jetzt compiliere, dann kommt als erstes ein Problem mit dem "inline":
warning: inline function: short rd::Random::rnd(...) const, used but never defined
Mh blöd. Also hab ich das inline weggemacht, und dann kam nur noch folgendes:.objs\main.o:main.cpp:(.text+0x13d): undefined reference to `rd::randomize'
collect2: ld returned 1 exit status
Process terminated with status 1 (0 minutes, 0 seconds)Auch blöd, hier der Code:
main.cpp
#include <iostream> #include "random.hpp" using namespace std; using namespace rd; int main() { cout << randomize.rnd(1,5) << "\n"; cout << "Hello world!" << endl; return 0; }random.hpp
namespace rd { class Random { public: Random(); short rnd(short interval_start, short interval_end) const; }; extern Random randomize; }random.cpp
#include <cstdlib> #include <ctime> #include "random.hpp" namespace rd { Random::Random() { srand(time(0)); rand(); } short Random::rnd(short interval_start, short interval_end) const { return (interval_start + rand() % (interval_end - interval_start + 1)); } }Was läuft da schief?
Wäre eigentlich ein "inline" bei der Methode "rnd" sinnvoll? Schon oder, is doch eine klitze klein winzige Methode. Hab in meinem Buch auch gelernt, Funktionen zwischen 1-2 Zeilen inline deklarieren.
Warum 1. "inline" nur im Header funktioniert, und
2. warum gibts dann überhaupt inline außerhalb des Headers, warum ist das nicht verboten? Und eigentlich ist es doch egal ob ich meine Methode in der Klasse definiere (ich weiß, da gibts eine Regel, die besagt, das alle Methoden die man in der Klasse definiert auotmatisch "inline" sind), oder in der .cpp wenn ich das doch übersichtlicher finde.
Ich glaub am besten nutz ich "inline" vorerst lieber gar nich mehr, bringt nur ärger mit sich
Und ich kan mir nicht vorstellen das mein Code dadurch so unglaublich schneller werden soll, wenn ich dazu dan nicht mal sagen kann obs am "inline" liegt, weil man ja nie sieht ob das "inline" vom Compiler beachtet wird oder nicht.MfG
Stromberg
-
ich hab dir eigentlich schon gesagt, lies dir etwas über übersetzungseinheiten durch und fang mit der ODR an

deklaration - sooft und wo du willst
definition - einmal im gesamten programm.Stromberg schrieb:
Hab weiter Probleme, also ich hab das "extern" Objekt im Header deklariert, weil in der .cpp wars ja falsch, weil man da definiert!
Wenn ich jetzt compiliere, dann kommt als erstes ein Problem mit dem "inline":
warning: inline function: short rd::Random::rnd(...) const, used but never definedwie schon gesagt, inline funktionen müssen in jeder übersetzungseinheit, in der sie verwendet werden, definiert sein.
.objs\main.o:main.cpp:(.text+0x13d): undefined reference to `rd::randomize'
collect2: ld returned 1 exit status
Process terminated with status 1 (0 minutes, 0 seconds)das bedeutet, dass rd::randomize nicht definiert ist. du deklarierst es zwar, aber es wird nirgendwo tatsächlich instanziiert.
Was läuft da schief?
Wäre eigentlich ein "inline" bei der Methode "rnd" sinnvoll?
wahrscheinlich ist es egal. wenn du den code oft austauschst eher nicht. ansonsten definiere die methode am besten direkt in der klassendefinition.
Schon oder, is doch eine klitze klein winzige Methode. Hab in meinem Buch auch gelernt, Funktionen zwischen 1-2 Zeilen inline deklarieren.
Warum 1. "inline" nur im Header funktioniert, und
2. warum gibts dann überhaupt inline außerhalb des Headers, warum ist das nicht verboten? Und eigentlich ist es doch egal ob ich meine Methode in der Klasse definiere (ich weiß, da gibts eine Regel, die besagt, das alle Methoden die man in der Klasse definiert auotmatisch "inline" sind), oder in der .cpp wenn ich das doch übersichtlicher finde.ich sagte: lies dir was zu übersetzungseinheiten durch. anscheinend muss ich wohl selbst ausholen

der compiler bekommt header-dateien niemals zu gesicht. ein compiler übersetzt immer nur einzelne übersetzungseinheiten.
was ist eine übersetzungseinheit?
wenn du dem compiler sagst, er soll eine datei, nennen wir sie foo.cc kompilieren, dann lässt er zunächst einmal den präprozesser drüberlaufen. der präprozessor ist eine textersetzungsmaschine. jedes #include <datei>, dass er in foo.cc findet, wird durch den inhalt der jeweiligen datei ersetzt. der kompiler bekommt am ende also nur noch eine foo.cc datei zu gesicht, in der alle includes durch die entsprechenden inhalte ersetzt sind. diese temporäre datei übersetzt der compiler nun - und das ist eben eine übersetzungseinheit.
der compiler macht nun idR eine weitere temporäre datei daraus, oft objektdatei genannt; das ist noch kein fertiges programm. die entitäten, die in dieser objektdatei nämlich nicht definiert sind, müssen irgendwo anders definiert sein (in einer anderen objektdatei). wenn du also in einer übersetzungseinheit eine variable als "extern" deklarierst, bedeutet das, dass der compiler sie in *dieser* übersetzungseinheit nicht initialisieren muss, weil sie in einer *anderen* übersetzungseinheit initialisiert (=definiert) wird.
man braucht nun also auch ein programm, das alle objektdateien durchsieht und die definitionen mit den deklarationen verbindet. das ist ein binder oder auch: linker.und der linker ist es auch, der die fehlermeldung "undefined reference to ..." ausgibt. er sucht nach einer definition, weil in einer objektdatei eine externe variable deklariert wird, findet aber in keiner übersetzungseinheit die tatsächliche variable. klar, dass das einen fehler erzeugt.
umgekehrt: wird in mehreren übersetzungseinheiten dieselbe variable definiert (und nicht manuell vor dem linker "versteckt"), dann findet der linker für eine deklaration mehrere mögliche definitionen (in verschiedenen objektdateien) und er gibt eine fehlermeldung à la "mulitple definitions found" aus.
und mit inline kann man genau dieses problem umgehen - dafür ist inline da.
-
Mh, so ganz versteh ich da was noch nicht. Schätzungsweise ich habe:
main.cpp#include "foo.hpp" int main() { return 0; }foo.hpp
#include "test.hpp" class B { }foo.cpp
#include "foo.hpp" B::B() { ..... }test.hpp
class test { }test.cpp
#include "test.hpp" test::test() { }1. Mit welcher Headerdatei wird begonnen?
2. Eigentlich sollte er doch mit "main.cpp" anfangen, weil dadurch werden ja alle Präprozessoredirektiven durchlaufen?
In "main.cpp" müsste doch dann eigentlich stehen:class B { } B::B() { ..... } class test { } test::test() { ..... } int main() { return 0; }Oder? Also gibt es doch nur eine Übersetzungseinheit (weil ich les immer was von Übersetzungseinheiten, aber warum)? Was bringt es erst "foo.hpp" zu durchlaufen, dann bekommt man ja nur die Headerdateien die bei "foo.hpp" drinstehen (hier "test.hpp"). Mit der "main.cpp" werden ja alle auf einen Schlag vom Präprozessor aufgelöst, main ist sozusagen die Grundwurzel und von ihr gehen ganz viele Wurzeln aus weg, und von diesen wieder welche.....
Warum also "Übersetzungseinheiten"?MfG
StrombergPS: Was sind "entitäten"?
-
du lässt deine programme anscheinend immer über deine IDE kompilieren
wenn du den compiler mal direkt in der konsole öffnen würdest, wäre dir einiges klarer.du rufst den compiler idR für jede *.cpp-datei auf. aus jeder *.cpp-datei wird also eine übersetzungseinheit.
wenn der präprozessor über die main.cpp drübergelaufen ist, sieht der code so aus:
class test { }; class B { }; int main () { };der code aus den anderen *.cpp dateien wird ja nirgends inkludiert (mit include), deshalb ist er in der übersetzungseinheit "main" auch nicht enthalten.
analog sieht bar.cpp dann nach dem präprozessor so aus:
class test { }; class B { }; B::B() { ..... }und test.cpp nach dem präprozessor so:
class test { }; test::test() { ..... }das macht drei übersetzungseinheiten.
und jetzt überprüfe mal, ob die one-definition rule stimmt: ist test::test() nur in einer übersetzungseinheit definiert? ja, in test.cpp. B::B ist nur in bar.cpp definiert und main nur in main.cpp."einen moment", wirst du sagen, was ist mit den definitionen der klassen?
die klassen test und B sind ja in allen drei übersetzungseinheiten definiert."ja", werde ich antworten, denn die ODR gilt für klassendefinitionen nicht. (3.2/5)
-
Stromberg schrieb:
PS: Was sind "entitäten"?
alles, was da ist. objekte, funktionen, klassen, templates, ...
-
Selbst wenn er die IDE benutzt: er brauch blos in das Output-Fenster der IDE schauen, da steht was alles passiert. Ist ja nicht so, das er ne Taste drückt und es wird ihm alles vorenthalten. Ja, auch der MSVC gibt alles aus. Man kann sogar das Verbose-Parameter mitgeben, dann wird man mit Infos überschüttet. Weiterhin kann man ja auch mal in das Projektverzeichnis schauen, da liegen auch die ganzen Objekt-Dateien. Und wenn man die im Explorer neben den dazugehörigen CPP-Dateien sieht... also, da muß einem ein Licht aufgehen!
-
Artchi schrieb:
Selbst wenn er die IDE benutzt: er brauch blos in das Output-Fenster der IDE schauen, da steht was alles passiert. Ist ja nicht so, das er ne Taste drückt und es wird ihm alles vorenthalten. Ja, auch der MSVC gibt alles aus. Man kann sogar das Verbose-Parameter mitgeben, dann wird man mit Infos überschüttet. Weiterhin kann man ja auch mal in das Projektverzeichnis schauen, da liegen auch die ganzen Objekt-Dateien. Und wenn man die im Explorer neben den dazugehörigen CPP-Dateien sieht... also, da muß einem ein Licht aufgehen!
ich formuliere es wohl lieber als "das war anscheinend die IDE" als "du bist wohl zu *** dafür"

-
Also den Kompiliervorgang hab ich jetzt mal TOP verstanden. Für die gute Erklärung schon mal ein Dankeschön.
Nur was eine Objektdatei genau ist, das ist mir noch nicht so ganz klar, bzw. irgendwie zu abstrakt. Also eine Übersetzungseinheit ist halt einfach eine große .cpp Datei, in der noch ganz viele Deklarationen drin stehen. Kann man eine Übersetzungseinheit noch in einem Editor anschauen? Oder is die schon irgendwie codiert, kp..?
Zumindestens, wird aus der Übersetzungseinheit ja dann eine Objektdatei erstellt. Ist diese noch für den Menschen lesbar, oder kann die nur noch der Linker lesen? Ist das schon irgendwie Binärcode...?
Nach dem alle Objektdateien gelinkt wurden, also die Deklarationen mit den Definitionen verbunden wurden, was kommt dann da raus? Kommt da schon die .exe raus? Die nur aus binärcode, bzw. Maschienencode besteht raus? Oder vll. eine Megaobjektdatei?
Geht es jetzt nochmal zurück vom Linker zum Compiler, der daraus letztendlich die .exe macht?Würde mich mal so interessieren. Ich hoffe das man hier jetzt nicht zu sehr ins Detail vom Computeraufbau etc. gehen muss, weil sonst fehlt mir wohl leider das nötige Vorwissen (bin kein Informatikstudent o.ä. nur n kleiner Hobby Porgrammierer). Wenn ja is auch nicht so schlimm.
Und noch was, du sagtest vorhin:
und mit inline kann man genau dieses problem umgehen - dafür ist inline da
Welche Probleme? Meinst du jetzt "multiple definitions found", "undefined reference to"....? Wie soll ich das mit "inline" lösen?
MfG
Stromberg