bad reloc address (Keine Bibliotheken verwendet)



  • Guten Tag.
    Ich hab folgendes Problem: Ich wollte einen Binärbaum in C++ implementieren. Allerdings machte mir da der Linker einen Strich durch die Rechnung:

    C:\Users\Ikaron\AppData\Local\Temp\ccn3NAsU.ltrans0.ltrans.o:ccn3NAsU.ltrans0.o:(.text.startup+0x9c): undefined reference to `BinaryTree<int>::add(int)'
    C:\Users\Ikaron\AppData\Local\Temp\ccn3NAsU.ltrans0.ltrans.o:ccn3NAsU.ltrans0.o:(.text.startup+0xb9): undefined reference to `BinaryTree<int>::printLayer(int)'
    e:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: C:\Users\Ikaron\AppData\Local\Temp\ccn3NAsU.ltrans0.ltrans.o: bad reloc address 0x0 in section `.ctors'
    collect2.exe: error: ld returned 1 exit status
    

    So rufe ich g++ auf:

    E:\MinGW\bin\g++.exe
    -IE:/workspace_cpp/test/src/
    E:/workspace_cpp/test/src/tree.cpp
    E:/workspace_cpp/test/src/tree.h
    E:/workspace_cpp/test/src/compare.h
    E:/workspace_cpp/test/src/main.cpp
    -o E:/workspace_cpp/test/out.exe
    -std=c++11 -march=native -Ofast -flto
    

    Ich verwende keine externe Bibliotheken. Ich finde nur einfach den Fehler nicht... Da ich aus der Java-Welt komme, wäre es sehr nett, wenn ihr mich auf eventuelle Fehler mit new und delete hinweist. Außerdem noch eine Frage, wie kann ich ein Programm mit MinGW kompilieren, ohne libgc_s_dw2-1.dll und libstdc++-6.dll zu benötigen und ohne, dass ein "Hello World" 1,5MB groß wird?
    Vielen Dank schonmal.

    Hier der Sourcecode:
    compare.h

    #ifndef _COMPARE_H
    #define _COMPARE_H
    
    template <typename T>
    class Comparator {
    
    public:
    	virtual int compare(T a, T b) = 0;
    };
    
    #endif
    

    tree.h

    #ifndef _TREE_H
    #define _TREE_H
    
    #include "compare.h"
    
    template <typename T>
    class TreeNode {
    
    protected:
    	Comparator<T>* comparator;
    
    public:
    	TreeNode(Comparator<T>* comparator) { this->comparator = comparator; };
    
    	virtual ~TreeNode();
    	virtual TreeNode<T>* add(T* t);
    	virtual void printLayer(int layer);
    };
    
    template <typename T>
    class DataNode : public TreeNode<T> {
    
    private:
    	T* content;
    	TreeNode<T>* nextLeft;
    	TreeNode<T>* nextRight;
    
    public:
    	DataNode(Comparator<T>* comparator, T* content) : TreeNode<T>(comparator) { this->content = content; };
    	DataNode(Comparator<T>* comparator, T* content, TreeNode<T>* nextLeft, TreeNode<T>* nextRight) : TreeNode<T>(comparator) { this->content = content; this->nextLeft = nextLeft; this->nextRight = nextRight; };
    	~DataNode() { delete content; delete nextLeft; delete nextRight; };
    
    	TreeNode<T>* add(T* t);
    	void printLayer(int layer);
    };
    
    template <typename T>
    class ExitNode : public TreeNode<T> {
    
    public:
    	ExitNode(Comparator<T>* comparator) : TreeNode<T>(comparator) {};
    	~ExitNode();
    
    	TreeNode<T>* add(T* t);
    	void printLayer(int layer) {};
    };
    
    template <typename T>
    class BinaryTree {
    
    private:
    	TreeNode<T>* root;
    	Comparator<T>* comparator;
    public:
    	BinaryTree(Comparator<T>* comparator) { this->comparator = comparator; this->root = new ExitNode<T>(comparator); };
    	~BinaryTree() { delete root; delete comparator; };
    
    	void add(T* t);
    	void add(T t);
    	void printLayer(int layer);
    };
    
    #include "tree.cpp"
    
    #endif
    

    tree.cpp

    #ifdef _TREE_H
    
    #include <iostream>
    
    #include "compare.h"
    
    template <typename T>
    TreeNode<T>* DataNode<T>::add(T* t) {
    
    	if(this->comparator->compare(*content, *t) > 0)
    		nextRight = nextRight->add(t);
    	else
    		nextLeft = nextLeft->add(t);
    
    	return this;
    }
    
    template <typename T>
    TreeNode<T>* ExitNode<T>::add(T* t) {
    
    	return new DataNode<T>(this->comparator, t, this, new ExitNode<T>(this->comparator));
    }
    
    template <typename T>
    void BinaryTree<T>::add(T* t) {
    
    	root = root->add(t);
    }
    
    template <typename T>
    void BinaryTree<T>::add(T t) {
    
    	root = root->add(&t);
    }
    
    template <typename T>
    void DataNode<T>::printLayer(int layer) {
    
    	if(layer == 0)
    		std::cout << content << " ";
    	else {
    		nextLeft->printLayer(layer - 1);
    		nextRight->printLayer(layer - 1);
    	}
    }
    
    template <typename T>
    void BinaryTree<T>::printLayer(int layer) {
    
    	root->printLayer(layer);
    }
    
    #endif
    

    main.cpp

    #include "compare.h"
    #include "tree.h"
    
    class IntComparator : public Comparator<int> {
    
    public:
    	int compare(int a, int b) {
    
    		return a - b;
    	}
    };
    
    int main(int argc, char** argv) {
    
    	BinaryTree<int>* tree = new BinaryTree<int>(new IntComparator());
    
    	for(int i = 0; i < 10; i++)
    		tree->add(i);
    
    	for(int i = 0; i < 10; i++)
    		tree->printLayer(i);
    
    	delete tree;
    
    	return 0;
    }
    


  • http://www.c-plusplus.net/forum/322658-full#2374823
    Am wichtigsten: Niemals new benutzen. Man kann sollte in C++ Objekte direkt deklarieren, was man in Java nicht kann. Benutze keine Vererbung wenn du es irgendwie verhindern kannst. Nachdem du das ganze unnötige Pointergefrickel raus nimmst verschwinden fast alle deine Probleme.



  • Bei Templates funktioniert die übliche Trennung in .h/.cpp nicht. Am einfachsten, du kopierst die Implementierungen aus tree.cpp in die tree.h.



  • Bashar schrieb:

    Bei Templates funktioniert die übliche Trennung in .h/.cpp nicht. Am einfachsten, du kopierst die Implementierungen aus tree.cpp in die tree.h.

    // TemplateClass.h
    #ifndef TEMPLATECLASS_H
    #define TEMPLATECLASS_H
    
    template<class T> class TemplateClass
    {
        public:
            TemplateClass();
    };
    
    #include "TemplateClass.cpp"
    #endif
    
    // TemplateClass.cpp
    #ifdef TEMPLATECLASS_H
    template <typename T> TemplateClass<T>::TemplateClass() {}
    #endif
    

    Oder hat das irgendwelche (mir nicht bekannten) Nachteile? Weil ich find das eigentlich ganz gut so, hoffe also dass nicht 😮



  • happystudent schrieb:

    Oder hat das irgendwelche (mir nicht bekannten) Nachteile? Weil ich find das eigentlich ganz gut so, hoffe also dass nicht 😮

    ist nicht das gleiche wie die Trennung in cpp/hpp



  • Ich hab mal versucht, den Workaround von happystudent zu implementieren. Die bad reloc addresses sind schon mal weg (von den Methoden), der Destruktor von TreeNode mag aber immer noch nicht:

    C:\Users\Ikaron\AppData\Local\Temp\ccXoQX1s.ltrans0.ltrans.o:ccXoQX1s.ltrans0.o:(.text+0x162): undefined reference to `TreeNode<int>::~TreeNode()'
    C:\Users\Ikaron\AppData\Local\Temp\ccXoQX1s.ltrans0.ltrans.o:ccXoQX1s.ltrans0.o:(.text+0x126): undefined reference to `TreeNode<int>::~TreeNode()'
    e:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: C:\Users\Ikaron\AppData\Local\Temp\ccXoQX1s.ltrans0.ltrans.o: bad reloc address 0x10 in section `.rdata'
    collect2.exe: error: ld returned 1 exit status
    

    Source code ist geupdated im ersten Post.

    Wie soll ich denn das Ganze ohne Pointer lösen @nwp3? Was ist so schlimm an new und delete, außer, dass man damit leicht Fehler macht?



  • Der Destruktor ist nirgends implementiert.



  • Bashar schrieb:

    Der Destruktor ist nirgends implementiert.

    Ich dachte, man könnte ihn einfach überschreiben, wie eine Methode... Wie kann ich denn den Destruktor umleiten auf die Kindklasse?



  • Der Destruktor der Basisklasse wird vom Destruktor der Kindklasse automatisch aufgerufen. Überschreiben hin oder her.



  • Bashar schrieb:

    Der Destruktor der Basisklasse wird vom Destruktor der Kindklasse automatisch aufgerufen. Überschreiben hin oder her.

    Also reicht praktisch ein leerer Destruktor für sowas?
    TreeNode* node = new ChildNode();
    delete node;
    Dann wird ChildNode::~ChildNode() aufgerufen, korrekt?
    Ändert allerdings nichts, wenn ich statt

    virtual ~TreeNode();
    
    ~TreeNode() {};
    

    schreibe. Immer noch das gleiche Problem.



  • Ikaron schrieb:

    Bashar schrieb:

    Der Destruktor der Basisklasse wird vom Destruktor der Kindklasse automatisch aufgerufen. Überschreiben hin oder her.

    Also reicht praktisch ein leerer Destruktor für sowas?
    TreeNode* node = new ChildNode();
    delete node;
    Dann wird ChildNode::~ChildNode() aufgerufen, korrekt?

    ja aber nur wenn der destruktor von TreeNode virtual ist.

    Und bei dir fehlt immer noch die implementierung des Destruktors von Treenode<T>



  • Hmm, ich habe den Destruktor auf virtual gesetzt, bekomme aber immer noch bad reloc address... Kannst du mir vllt bitte ein konkretes Beispiel geben, wie ich sowas mache?

    template <class A> class Base {
    
    public:
    	virtual ~Base();
    };
    
    template <class A> class Child : public Base<A> {
    
    public:
    	~Child() { /* ... */ };
    };
    

    Ist das prinzipiell richtig?



  • Ikaron schrieb:

    Hmm, ich habe den Destruktor auf virtual gesetzt, bekomme aber immer noch bad reloc address... Kannst du mir vllt bitte ein konkretes Beispiel geben, wie ich sowas mache?

    typedef <class A> class Base {
    
    public:
    	virtual ~Base();
    };
    
    typedef <class A> class Child : public Base<A> {
    
    public:
    	~Child() { /* ... */ };
    };
    

    Ist das prinzipiell richtig?

    ne da steht typedef obwohl du wohl eher template möchtest.



  • asfdlol schrieb:

    Ikaron schrieb:

    Hmm, ich habe den Destruktor auf virtual gesetzt, bekomme aber immer noch bad reloc address... Kannst du mir vllt bitte ein konkretes Beispiel geben, wie ich sowas mache?

    typedef <class A> class Base {
    
    public:
    	virtual ~Base();
    };
    
    typedef <class A> class Child : public Base<A> {
    
    public:
    	~Child() { /* ... */ };
    };
    

    Ist das prinzipiell richtig?

    ne da steht typedef obwohl du wohl eher template möchtest.

    Ehm upps, klaro, ich verwechsel die zwei immer. Tu so als würde da template stehen.



  • Ob es was bringt, dir zum dritten mal zu sagen, dass der Destruktor nicht implementiert ist? Man kanns ja mal probieren.



  • Bashar schrieb:

    Ob es was bringt, dir zum dritten mal zu sagen, dass der Destruktor nicht implementiert ist? Man kanns ja mal probieren.

    Ich verstehe nicht, was daran nicht implementiert sein soll... Habe schon versucht, deinen Tipp umzusetzen, aber am Fehler hat das nie was geändert. Außerdem meckert ja nicht mal der Compiler, sondern nur der Linker.

    ~BinaryTree() { delete root; delete comparator; };
    
    virtual ~TreeNode() {};
    ~DataNode() { delete content; delete nextLeft; delete nextRight; };
    ~ExitNode() {};
    


  • Ikaron schrieb:

    Ich verstehe nicht, was daran nicht implementiert sein soll...

    Sorry, hab nicht mitbekommen, dass du den implementiert hast. In deinen letzten Postings seh ich jedenfalls nichts davon.

    Habe schon versucht, deinen Tipp umzusetzen, aber am Fehler hat das nie was geändert.

    Das bezweifle ich. Poste doch mal die aktuelle Fehlermeldung.

    Außerdem meckert ja nicht mal der Compiler, sondern nur der Linker.

    Das ist ja auch ein typischer Linkerfehler, weil Funktionen auch in anderen Übersetzungseinheiten definiert werden können (und in der Regel auch werden.)

    ~BinaryTree() { delete root; delete comparator; };
    
    virtual ~TreeNode() {};
    ~DataNode() { delete content; delete nextLeft; delete nextRight; };
    ~ExitNode() {};
    

    Und der Linker sagt immer noch "undefined reference to TreeNode<int>::~TreeNode()"? Kann ich mir kaum vorstellen.



  • Bashar schrieb:

    Ikaron schrieb:

    Ich verstehe nicht, was daran nicht implementiert sein soll...

    Sorry, hab nicht mitbekommen, dass du den implementiert hast. In deinen letzten Postings seh ich jedenfalls nichts davon.

    Ja, ich hab ein wenig rumprobiert, aber es letztendlich wieder gestrichen, da sich nichts geändert hat.

    Bashar schrieb:

    Habe schon versucht, deinen Tipp umzusetzen, aber am Fehler hat das nie was geändert.

    Das bezweifle ich. Poste doch mal die aktuelle Fehlermeldung.

    C:\Users\Ikaron\AppData\Local\Temp\ccLuai9r.ltrans0.ltrans.o:ccLuai9r.ltrans0.o:(.text+0x137): undefined reference to `TreeNode<int>::~TreeNode()'
    C:\Users\Ikaron\AppData\Local\Temp\ccLuai9r.ltrans0.ltrans.o:ccLuai9r.ltrans0.o:(.text+0x10b): undefined reference to `TreeNode<int>::~TreeNode()'
    e:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: C:\Users\Ikaron\AppData\Local\Temp\ccLuai9r.ltrans0.ltrans.o: bad reloc address 0x10 in section `.rdata'
    collect2.exe: error: ld returned 1 exit status
    

    Bashar schrieb:

    Außerdem meckert ja nicht mal der Compiler, sondern nur der Linker.

    Das ist ja auch ein typischer Linkerfehler, weil Funktionen auch in anderen Übersetzungseinheiten definiert werden können (und in der Regel auch werden.)

    Komisch, bei mir hat sich der Compiler vorhin erst beschwert.

    Bashar schrieb:

    ~BinaryTree() { delete root; delete comparator; };
    
    virtual ~TreeNode() {};
    ~DataNode() { delete content; delete nextLeft; delete nextRight; };
    ~ExitNode() {};
    

    Und der Linker sagt immer noch "undefined reference to TreeNode<int>::~TreeNode()"? Kann ich mir kaum vorstellen.

    Jap. Fehlermeldung steht oben.



  • Ikaron schrieb:

    Bashar schrieb:

    Ikaron schrieb:

    Ich verstehe nicht, was daran nicht implementiert sein soll...

    Sorry, hab nicht mitbekommen, dass du den implementiert hast. In deinen letzten Postings seh ich jedenfalls nichts davon.

    Ja, ich hab ein wenig rumprobiert, aber es letztendlich wieder gestrichen, da sich nichts geändert hat.

    Was hast du gestrichen? Die Implementierung?

    Bashar schrieb:

    Habe schon versucht, deinen Tipp umzusetzen, aber am Fehler hat das nie was geändert.

    Das bezweifle ich. Poste doch mal die aktuelle Fehlermeldung.

    C:\Users\Ikaron\AppData\Local\Temp\ccLuai9r.ltrans0.ltrans.o:ccLuai9r.ltrans0.o:(.text+0x137): undefined reference to `TreeNode<int>::~TreeNode()'
    C:\Users\Ikaron\AppData\Local\Temp\ccLuai9r.ltrans0.ltrans.o:ccLuai9r.ltrans0.o:(.text+0x10b): undefined reference to `TreeNode<int>::~TreeNode()'
    e:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: C:\Users\Ikaron\AppData\Local\Temp\ccLuai9r.ltrans0.ltrans.o: bad reloc address 0x10 in section `.rdata'
    collect2.exe: error: ld returned 1 exit status
    

    Besagt eindeutig, dass der Destruktor vom Linker nicht gefunden wurde. Entweder du hast ihn nicht implementiert oder du hast ihn in einer anderen .cpp implementiert.

    Bashar schrieb:

    Komisch, bei mir hat sich der Compiler vorhin erst beschwert.

    Sicher nicht über "undefined references".



  • Bashar schrieb:

    Ikaron schrieb:

    Bashar schrieb:

    Ikaron schrieb:

    Ich verstehe nicht, was daran nicht implementiert sein soll...

    Sorry, hab nicht mitbekommen, dass du den implementiert hast. In deinen letzten Postings seh ich jedenfalls nichts davon.

    Ja, ich hab ein wenig rumprobiert, aber es letztendlich wieder gestrichen, da sich nichts geändert hat.

    Was hast du gestrichen? Die Implementierung?

    Naja, ich hab alle Klammern hin und her geschoben... Aber gebracht hat es mir nicht, deswegen hab ich es jetzt einfach so gelassen, wie ich es vorhin geschrieben hab.

    Bashar schrieb:

    Bashar schrieb:

    Habe schon versucht, deinen Tipp umzusetzen, aber am Fehler hat das nie was geändert.

    Das bezweifle ich. Poste doch mal die aktuelle Fehlermeldung.

    C:\Users\Ikaron\AppData\Local\Temp\ccLuai9r.ltrans0.ltrans.o:ccLuai9r.ltrans0.o:(.text+0x137): undefined reference to `TreeNode<int>::~TreeNode()'
    C:\Users\Ikaron\AppData\Local\Temp\ccLuai9r.ltrans0.ltrans.o:ccLuai9r.ltrans0.o:(.text+0x10b): undefined reference to `TreeNode<int>::~TreeNode()'
    e:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: C:\Users\Ikaron\AppData\Local\Temp\ccLuai9r.ltrans0.ltrans.o: bad reloc address 0x10 in section `.rdata'
    collect2.exe: error: ld returned 1 exit status
    

    Besagt eindeutig, dass der Destruktor vom Linker nicht gefunden wurde. Entweder du hast ihn nicht implementiert oder du hast ihn in einer anderen .cpp implementiert.

    Hmm, magst du mir vllt kurz über Skype helfen? Wenn ein Profi das macht geht es sicher in 5 Minuten...



  • ... Es hat sich doch schon erledigt. Ich habe, intelligent wie ich bin, noch ein Backup-Verzeichnis gehabt, wo ich brav eure Vorschläge befolgt habe... Stellt sich heraus, dass das gar nicht mein Source-Verzeichnis war. Danke noch mal für die Tipps...
    (So ein Anfängerfehler, könnte mir grade echt so in's Gesicht schlagen...)


Log in to reply