Auskopplungen und inkludieren von Headern (Linkerfehler: Unresolved External)



  • Nachdem ich ein Template in einer separaten cpp und h Datei erstellt habe,
    bekam ich einen Linkerfehler:
    [Linker Fehler] Unresolved external 'void foo<Test>(_STL::list<foo *, _STL::allocator<foo *> > *, _STL::_List_iterator<foo *, _STL::_Nonconst_traits<foo *> >&)' referenced from C:\Project1\UNIT2.OBJ

    Daraufhin habe ich das Template zu Testzwecken durch eine Funktion ersetzt.
    Wie im folgenden Beschrieben gab es da auch Probleme.
    Ich würde mich freuen wenn jemand Hinweise hätte.

    Mit Borland C++ Builder 6,
    (bei Erstellung im Konsolen-Experte "C++" und "Konsolen-Anwendung" aktiv,
    aus Standard-Borland-Vorlage z.B pragma-Direktiven entfernt
    wo hier kein sichtbarer Effekt):

    Unit1.cpp:

    #include "Unit2.h" //
    int main(int argc, char* argv[])
      {
      return 0;
      }
    

    Unit2.cpp:

    #include "Unit2.h" // In Unit1.cpp sollen Definitionen aus Unit2.h bekannt sein.
    

    Unit2.h:

    // Wenn ifndef auskommentiert
    // [C++ Fataler Fehler] Unit2.h(6): F1005 Include-Dateien zu tief verschachtelt
    // ansonsten
    // [C++ Fehler] Unit3.h(9): E2147 Parameterdeklaration darf nicht mit 'Test' beginnen
    // BCB-Hilfe zu E2147:
    // Ein nicht definierter Bezeichner wurde am Anfang eines Arguments in einer Funktionsdeklaration entdeckt.
    // Kommentar: Vielleicht etwas wie "Undefiniertes Symbol".
    
    //#ifndef Unit2H
    //#define Unit2H   
    #include "Unit3.h" // In Unit2.cpp sollen Definitionen aus Unit3.h bekannt sein.
    class Test
      {
      };
    //#endif
    

    Unit3.cpp:

    #include "Unit3.h"
    foo()
      {
      }
    

    Unit3.h:

    #include "Unit2.h" // In Unit3.cpp und Unit3.h sollen Definitionen aus Unit2.h bekannt sein.
    foo(Test tst);     // Schon wegen der Verwendung des Datentyps der Klasse Test.
                       // Nebenfrage: Währe das Include auch für ein Template nötig,
                       // in welchem der Datemtyp mit typename und einer Variablen definiert ist ?
    

    Können die Headerdateien richtiger oder resourcenschonender inkludiert werden ?
    Sollten externe Bibliotheken in den jeweiligen h
    und nicht in cpp dateinen inkludiert werden,
    auch wenn sie in den h dateinen nicht verwendet werden ?



  • Ui, ui...

    Zum einen müssen Templates immer komplett im Header definiert werden (damit bei Benutzung dieses Templates in einer anderen Übersetzungseinheit (ÜE) diese komplett bekannt ist).

    Und zum anderen darfst du beim Einbinden von Headerdateinen keine Cross-Reference erzeugen (du bindest in Unit2.h den Header Unit3.h ein, welcher wieder Unit2.h einbindet etc.) - und auf die Include-Guards (#pragma bzw. #ifndef) solltest du auch nicht verzichten.



  • fuse schrieb:

    Sollten externe Bibliotheken in den jeweiligen h
    und nicht in cpp dateinen inkludiert werden,
    auch wenn sie in den h dateinen nicht verwendet werden ?

    Nur was benötigt wird im Header einbinden.



  • Es wurde zwar schon alles gesagt, trotzdem noch eine kleine Anmerkung:

    Da #include de facto nichts anderes als Copy+Paste ist, kann man auf den ersten Blick seltsame Include-Probleme meistens ganz gut verstehen,
    indem man einfach mal selbst "Präprozessor" spielt, und Includes manuell in einer separaten Textdatei auflöst. Dabei merkt man meiner Erfahrung
    nach recht schnell, was da faul ist. Z.B. so eine Endlosrekursion oder Verwendung von nicht deklarierten/unvollständigen Typen.



  • Ich hatte dann das #include "Unit2.h" in Unit3.h herausgenommen. Danke 🙂

    Wieso erstellt der Borland C++ Builder (BCB) für die Unit1.cpp keine Header-Datei ?
    Ist es üblich, dort dann Unit2.h einzubinden ?

    Mit den Anweisungen "#pragma hdrstop" und "#pragma package(smart_init)"
    hatte ich mit Linux g++ einen Fehler bekommen. Zwischenzeitlich sind es die Warnungen:

    Ignoring #pragma hdrstop [-Wunknown-pragmas]
    Ignoring #pragma package [-Wunknown-pragmas]

    Gibt es diesbezüglich pragmas, welche auch Linux g++ kennt ?

    #pragma argsused unterdrückt nach der BCB Hilfe
    die Warnung, "Parameter wird nie benutzt" oder ähnlich.
    Auf #ifndef hatte ich speziell im Beispiel verzichtet.

    Bezüglich der Auskopplung von Templates hatte ich auf
    http://stackoverflow.com/questions/648900/c-templates-undefined-reference#648905
    den Hinweis gefunden, daß das Auskoppeln von Templates
    noch nicht richtig untersützt zu werden scheint,
    und es daher ratsam ist diese hierzu in einer Header-Datei zu definieren.
    Dennoch hatte ich diesbezüglich diese Compiler-Warnung bekommen:

    [C++ Warnung] TDeleteListAndTheirElements.cpp(3): W8058 Präcompilierter Header: Header unvollständig kann nicht erzeugt werden

    Derzeit ist sie verschwunden. Vielleicht wegen dem Wiedereinfügen von "#pragma hdrstop".

    Der Zweck dieses Templates ist das Freigeben von Speicherbereichen,
    welche durch Zeiger in std::list allokiert werden.
    Mit der ptr_list von boost gabe es mit dem BCB
    den folgenden Fehler in einer Header-Datei daraus:

    [C++ Fehler] remove_cv.hpp(22): E2238 Bezeichner 'remove_cv<T>' mehrfach deklariert

    Vielleicht versuche ich einem Child von std::list
    den delete-Opperator zu überladen, so daß
    auch die genannten Speicherbereiche freigegeben werden.



  • #ifndef Includeguards sind der portable Weg.

    Speicherverwaltung:

    std::list< std::unique_ptr< Foo > > l;
    

Log in to reply