Kompilieren einer Klasse schlägt fehl



  • Hey Leute,

    ich bin dabei mir C++ beizubringen und habe mich gestern daran versucht eine neue Klasse zu erstellen. Es soll ein einfacher Array beliebiger Länge erstellt werden, dessen Länge abrufbar sein soll.
    Nachdem ich gestern mehrere Stunden damit verbracht habe heraus zu finden wo der Fehler im Code ist poste ich ihn jetzt einmal. Beim kompilieren mit g++ erhalte ich folgende Fehlermeldung:

    In file included from test.cpp:2:0:
    myArray.h:12:11: error: expected unqualified-id before ‘int’
       myArray(int laenge);
               ^
    myArray.h:12:11: error: expected ‘)’ before ‘int’
    myArray.h:13:11: error: expected class-name before ‘(’ token
       ~myArray();
               ^
    myArray.h:9:1: error: an anonymous struct cannot have function members
     {
     ^
    myArray.h:21:1: error: abstract declarator ‘<anonymous class>’ used as declaration
     };
     ^
    test.cpp: In function ‘int main()’:
    test.cpp:8:10: error: ‘a’ was not declared in this scope
      myArray a=myArray(4);
    

    meine Header Datei myArray.h sieht folgendermaßen aus:

    #ifndef myArray
    #define myArray
    
    #include <iostream>
    using namespace std;
    
    class myArray
    {
    
    	public:
    		myArray(int laenge);
    		~myArray();
    
    		int len();
    		float* getArray();
    
    	private:
    		int length;
    		float* location;
    };
    
    #endif
    

    und meine myArray.cpp

    #include"myArray.h"
    #include<iostream>
    
    using namespace std;
    
    myArray::myArray(int laenge)
    {
    	length=laenge;
    	location = new float[laenge];
    	for(unsigned int i=0;i<laenge;++i)	location[i]=0;
    }
    
    myArray::~myArray()
    {
    	delete[] location;
    	delete length;
    }
    
    int myArray::len()	return length;
    
    float* myArray::getArray()	return location;
    

    aufgerufen wird das ganze mit test.cpp:

    #include<iostream>
    #include"myArray.h"
    
    using namespace std;
    
    int main()
    {
    	myArray a=myArray(4);
    	//cout<<myArray.len()<<endl;
    }
    

    Vielen Dank schon einmal im voraus 🙂

    F



  • Hi!

    Beachte deine Präprozessor-Defines: #define myArray --> #define myArray_HPP z.B. Deshalb ist es oft üblich, Präprozessor-Makros immer in Caps zu schreiben, also MYARRAY_HPP, um solche Namenskollisionen zu verhindern.

    Der Compiler sieht class myArray und ersetzt das myArray durch '', also garnichts.



  • Alles klar, vielen Dank, hab mir darüber jetzt etwas durchgelsen, mir war vorher gar nicht wirklich klar warum man das macht, in einigen Beispielen die ich gefunden hatte kam es auch gar nicht vor 🙂
    Jetzt ist die Fehlermeldung schon mal kürzer geworden. Es bleibt:

    /tmp/ccbzYrKJ.o: In function `main':
    test.cpp:(.text+0x15): undefined reference to `myArray::myArray(int)'
    test.cpp:(.text+0x21): undefined reference to `myArray::~myArray()'
    collect2: error: ld returned 1 exit status
    


  • Hallo FrankDrebin

    Das ist ein Linker-Fehler. Was er dir damit sagen möchte, ist, dass er die Definition von myArray::myArray(int) und myArray::~myArray() nicht ausfindig machen konnte. Ich nehme an, du kompilierst direkt im Terminal, ohne GNU Make / CMake? Dann müsste der Befehl so aussehen: g++ test.cpp myArray.cpp
    Damit bezweckst du, dass der Compiler beide Dateien kompiliert und danach miteinander zu einem Programm verlinkt.

    LG



  • Ah, vielen Dank für die Hilfe :))
    Danach habe ich noch andere Fehler im Code gefunden aber mit den Fehlermeldungen konnte ich dann etwas anfangen.
    Zum Einen darf ich wohl Funktionen nicht ohne Klammer in einer Zeile definieren, zum Anderen habe ich jetzt aber noch eine hoffentlich letzte Frage zum Destructor.
    Ich lösche im Destructor den Array, den integer wollte er aber nicht löschen und fragt stattdessen nach einem Pointer. Liegt das daran, dass der Integer im Stack liegt und auch ohne mein Zutun automatisch gelöscht wird und der Array im Heap und deswegen manuell gelöscht werden muss? Oder bleibt, wenn ich

    delete length;
    

    ausklammere der Integer noch irgendwo im Speicher?

    Vielen Dank an Alle,

    F



  • FrankDrebin schrieb:

    Liegt das daran, dass der Integer im Stack liegt und auch ohne mein Zutun automatisch gelöscht wird und der Array im Heap und deswegen manuell gelöscht werden muss?

    Exakt.

    Grundsätzlich gilt: für jedes new ein delete , für jedes new[] ein delete[] . Für length hast du kein new gebraucht, daher ist auch kein delete vonnöten.



  • Du musst bei deinem Ansatz auch die Regel der Großen Drei/Fünf beachten, um kein Undefiniertes Verhalten zu erzeugen. Oder du gibst die manuelle Speicherverwaltung auf und benutzt std::vector zur Ablage der Datenelemente in deinem Array.

    Edit:
    Überhaput solltest du einen Blick in die STL werfen und so viele STL Algorithmen wie möglich benutzen. Die for-Schleife zum Initialisieren der Elemente lässt sich durch std::fill realisieren (wenn du partout bei manueller Speicherverwaltung bleiben möchtest).

    int main()
    {
       myArray a1( 100 );
       myArray a2 = a1; // ==> boom!
    }
    

    Außerdem solltest du den Parameter laenge durch einen unsigned-Datentyp ersetzen. Dein Code lässt aktuell das Erstellen von Arrays mit einer Länge von z.B. -5 zu, was vollkommener Quatsch ist.

    myArray::myArray( std::size_t laenge)
    {
       location = new float[laenge];
       std::fill( location, location + laenge, 0 );
    }
    


  • Besorg dir ein anständiges Buch!


  • Mod

    Fytch schrieb:

    FrankDrebin schrieb:

    Liegt das daran, dass der Integer im Stack liegt und auch ohne mein Zutun automatisch gelöscht wird und der Array im Heap und deswegen manuell gelöscht werden muss?

    Exakt.

    Grundsätzlich gilt: für jedes new ein delete , für jedes new[] ein delete[] . Für length hast du kein new gebraucht, daher ist auch kein delete vonnöten.

    Und noch grundsätzlicher gilt: Kein new und delete! Wenn man nicht gerade eine Ressorucenverwaltungsklasse schreibt, dann hat Ressourcenverwaltung in einer selbstprogrammierten Klasse nichts zu suchen. Stattdessen nehme man Komposition mit einer fertigen Ressourcenverwaltungsklasse, d.h. in aller Regel einen Container oder Smartpointer aus der Standardbibliothek.

    Und wenn man eine Ressourcenverwaltungsklasse schreiben sollte, dann sollte man es wenigstens richtig machen und die Begriffe "RAII" und "Rule of 3" (oder neuerdings "Rule of 5") kennen.

    Das Array hier ist hart an der Grenze bezüglich der Frage, ob es Ressourcen verwalten sollte oder nicht. Kommt drauf an, ob man den Begriff "Array" eher als den unterliegenden Speicher versteht, oder als das Zugriffsmodell. Wenn wir hier im Zweifel für den Angeklagten plädieren und annehmen, dass hier wirklich Speicher verwaltet werden soll, dann hat der Threadersteller aber die Rule of 3/5 verletzt und muss diesen Fehler unbedingt sofort beheben.


Log in to reply