namespace Problem
-
Okay, dann is so wohl besser:
main.cpp
#include <iostream> #include "random.hpp" using namespace std; using namespace rd; int main() { cout << randomize.rnd(1,5) << "\n"; //!!! <-- Geht nicht cout << "Hello world!" << endl; return 0; }random.hpp
namespace rd { class Random { public: Random(); inline short rnd(short interval_start, short interval_end) const; }; }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)); } extern Random randomize; }1. Warum funktioniert das mit dem extern Objekt nicht?
2. Was muss ich machen, dass das "inline" bei meine Methode "rnd" klappt? Bzw. wie kann ich sehen obs verwendet wird oder nicht?MfG
Stromberg
-
extern Random randomize;das ist eine deklaration und keine definition. dein objekt gibt es also nicht (in der FAQ steht was zum unterschied zwischen deklaration und definition). lass also einfach das extern in der .cpp weg, in den header kommt dann:
namespace rd { class Random { public: Random(); inline short rnd(short interval_start, short interval_end) const; }; extern Random randomize; }Stromberg schrieb:
Was muss ich machen, dass das "inline" bei meine Methode "rnd" klappt? Bzw. wie kann ich sehen obs verwendet wird oder nicht?
gar nicht.
ansonsten könntest du dem compiler zumindest ermöglichen, den code zu inlinen, indem du ihn in den header hievst:
//random.hpp namespace rd { class Random { public: Random(); /* implizit inline */ short rnd(short interval_start, short interval_end) const { /* hier der code * } }; }du solltest dir unbedingt etwas über übersetzungseinheiten durchlesen, dann wird dir sowohl das mit extern als auch inline klarer. startpunkt könnte ein text über die one-definition-rule sein (google mal danach)
-
queer_boy schrieb:
außerdem wird dein inline mit ziemlicher sicherheit nicht tatsächlich geinlined. (außer bei einem sehr intelligenten linker)
Davon abgesehen ist es undefiniert. Es gibt keinen guten Grund, inline in irgendeiner Deklaration zu verwenden, die keine Definition ist.
-
Es gibt keinen guten Grund, inline in irgendeiner Deklaration zu verwenden, die keine Definition ist.
Versteh ich ned ! zu was ist dann inline eigentlich da ... ?
header definierte funktionen versucht er automatisch zu inlinen, da brauch ich das schluesselwort eigentlich nicht ....
und warum sollt ich funktionen, die ich getrennt deklariere und definiere ned inlinen koennen ?
Auch wenn die funktion selber kurz und knapp ist, kann es von nachteil sein, wenn ich die definition und deklaration ned trenne, siehe abhaengigkeiten und PIMPL Idom (als Besipiel das man sogar Anstrengungen in Kauf nimmt um abhaengigkeiten zu vermeiden) ...Ciao ....
-
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)