"ungültige Gleitkommaoperation" in Funktion, die nichts berechnet



  • Hat Soil* soilgrid[xsize][ysize]; die konstanten Grenzen xsize und ysize oder wird es dynamisch erzeugt?
    Falls ja: zeig mal die entsprechende Codestelle.

    Erbt Soil von anderen Klassen?
    Falls ja: Was passiert in den Konstruktoren der Superklassen?



  • Die Grenzen vom Array sind konstant. Wie die anderen arrays auch (alle der Größe xsize*ysize und xsize und ysize sind Konstanten).

    Soil erbt nicht von anderen Klassen.



  • Noch mal ne ganz grundsätzliche Frage:
    Bislang dachte ich bei einem Fehler immer, wenn ich irgendwas auskommentiere, und dann läuft es über diese Fehlerstelle drüber, dann ist die URsache im Auskommentierten zu suchen. Aber ist das zwingend so?



  • Jetzt scheint es zu klappen.

    Also ursprünglich war es so (=was ich vorher in main schrieb, aber da hatte ich die Initialisierung von dem Code meiner Kollegin (=das mit der for-Schleife und dem Soil =initialiseSoil) nicht mit aufgeführt).

    int main(int argc, char* argv[])
    {
            A* a;
    
    	initialiseSoil();
            a=new A();
            a->calculate();
            return 0;
    }
    

    Nun hab ich die Objekterzeugung von Klasse A vorgezogen, damit geht es.

    int main(int argc, char* argv[])
    {
            A* a;
    
    	a=new A();
    	initialiseSoil();
            a->calculate();
            return 0;
    }
    

    Kann man daraus irgendwelche Schlüsse ziehen?
    Ich bin jetzt erstmal total froh, daß es soweit läuft (und muß da erstmal wieder aufräumen). Aber eine wirkliche Fehlerlösung ist das ja nicht. Und wo ich den Fehler dann suchen soll, weiß ich immer noch nicht.
    Seht ihr da noch irgendwas, wo man das eingrenzen kann? Seht ihr das noch wie vor als Problem mit Pointern?
    (Das mit den SmartPointern ist ja schön, aber da verstehe ich noch zu wenig, wie man Code von ganz woanders her einbindet -zumindest mein Eindruck nach Überfliegen der Webseite)



  • Es könnte sein, dass du den Fehler nur wieder verschiebst. Aber wenn es geht, dann ist ja schon einmal gut.
    Kommt halt drauf an, was du alles in initialiseSoil machst. Ich habe mittlerweile die Übersicht über deinen Code verloren. 😉 - Darum wäre ein wirklich lauffähige Version, die den Fehler enthält praktisch gewesen.


  • Administrator

    drakon schrieb:

    Darum wäre ein wirklich lauffähige Version, die den Fehler enthält praktisch gewesen.

    Nicht nur läuffähig, sondern am besten auch noch lesbar.

    susie schrieb:

    Und ich glaube auch nicht, daß die Originalbezeichnungen viel weiterhelfen würden, wenn man die Anwendung nicht kennt.

    So einer Aussage kann ich nur widersprechen. Es ist äusserst unangenehm, wenn man sich irgendwelche Buchstaben als Klassen erinnern muss. Es ist deutlich lesbarer, wenn man die Funktion der Klasse gleich an ihrem Namen ablesen kann. Dies gilt übrigens auch für die Variablen.

    A a;
    B b = a.b();
    C* c = b.do_a();
    c->xyz();
    

    Da versteht ja niemand, was hier abgeht. Und wenn das über mehrere hundert Zeilen so abgeht, dann ist das für den Leser eher Buchstabensuppe als Programmcode 😉

    Grüssli



  • Was in initialiseSoil passiert, weiß ich auch nicht, ich kenne den Code ja auch nicht wirklich, ist ja nicht meiner.

    Hm, das gesamte Programm sind 24 Klassen, insgesamt 411 KB Quelltext (weiß nicht, wieviel Lines of Code), manches davon BorlandBuilder-spezifisch. Meint ihr, das geht überhaupt und bringt was, es so zu posten?
    Ich bin da auch ein bißchen zögerlich, das alles 1:1 öffentlich zu posten, weil es nicht nur mein Code ist und alles halt nichts privates.
    Oder kann ich das jemandem als Mail schicken? Macht zu Testzwecken aber auch nur Sinn, denk ich mal, wenn man es mit dem BorlandBuilder testen kann?!


  • Administrator

    Eine lauffähige Version muss nicht das ganze Programm sein. Nur der wesentliche Teil, wo der Fehler auftritt. Das können schlussendlich auch nur 20 Zeilen sein, müssen aber eben ausführbar sein.

    Solche kleine Test-Programme helfen einem auch selber, da man dadurch den Fehler eingrenzen kann.

    Den anderen hilft es, dass sie den Debugger verwenden und sich die Fehler selber anschauen können. Zudem ist ein kleiner Code deutlich schneller zu verstehen, als ein ganzes Projekt. Wodurch der Fehler deutlich schneller gefunden werden dürfte.

    Und wegen initialiseSoil:
    Naja, so wie es aussieht, könnte von dort der Fehler kommen. Oder zumindest könnte der Code dort drin mit dem Code in deinem A Konstruktor zusammenhängen. Daher wäre es schon praktisch, wenn du wüsstest, was dort drin vorgeht 😉

    Grüssli



  • Hallo,

    so, jetzt mache ich mich systematischer auf die Fehlersuche, durchsuche erstmal ob alle new's ein entsprechendes delete haben und ob die Pointer alle mit 0 initialisiert werden. Mein eigener Code scheint soweit ok, nun bin ich an dem Code meiner Kollegin. Dabei ist mir folgendes aufgefallen:

    Und zwar ist veggrid eine Instanzvariable einer Klasse:

    Veg* veggrid[xsize][ysize];
    

    im Konstruktor der Klasse passiert folgendes (in einer Schleife für die Indizes):

    veggrid[i][j] = new Veg();
    

    im Destruktor der Klasse (auch in einer Schleife):

    veggrid[i][j]->~Veg();
    

    Ich hätte in der Situation im Destruktor folgendes gemacht (auch in einer Schleife):

    delete veggrid[i][j];
    

    Nun bin ich ein bißchen irritiert. Kommt das auf dasselbe raus? Oder was ist besser?

    Danke mal wieder!



  • susie schrieb:

    im Destruktor der Klasse (auch in einer Schleife):

    veggrid[i][j]->~Veg();
    

    Ich hätte in der Situation im Destruktor folgendes gemacht (auch in einer Schleife):

    delete veggrid[i][j];
    

    Nun bin ich ein bißchen irritiert. Kommt das auf dasselbe raus? Oder was ist besser?

    Die erste Variante ist schlicht und einfach falsch. Den Destruktor direkt aufzurufen ist nur im Zusammenhang mit Placement-New sinnvoll, und das liegt hier ja nicht vor.

    Delete ruft automatisch den richtigen Destruktor auf, bevor es den Speicher freigibt. Der Destruktoraufruf alleine gibt aber den Speicher des Objekts nicht frei, d.h. im besten Fall hast du dadurch zumindest ein Speicherleck.



  • Hallo,

    das Problem zu Anfang des Jahres schien gelöst zu sein, jedenfalls lief es wieder, nachdem ich den Code nochmal durchforstet habe und sämtliche Instanzvariablen incl. Pointer initialisiert habe. Das Hauptproblem war wohl tatsächlich die Nichtinitialisierung einiger Instanzvariablen und der mangelhafte Destruktor wie oben beschrieben. Der Code lief dann die ganze Zeit, auch als ich einige kleine Änderungen gemacht habe.
    Nun habe ich einige "umfangreichere" Änderungen gemacht. Na ja, hab in einer Klasse 2 Arrays als Instanzvariablen eingefügt und in einer anderen Klasse eine double-Instanzvariable und entsprechende Zugriffsfunktionen implementiert. Jedenfalls stehe ich nun wieder vor demselben Problem: Ich bekomme die Fehlermeldung "Ungültige Gleitkommaoperation", obwohl da keine Gleitkommaoperation ist. Durch Auskommentieren ließ sich der Fehler darauf beschränken, daß er auftritt, wenn ich die double-Instnazvariable mit einer "set..."-Methode setze, und das tritt in der Anfangsphase des Programms auf, vor den eigentlichen Berechnungen. Ich habe jetzt in der set-Methode dummy-Werte von 0.5 zugewiesen, aber trotzdem. Also wird es wohl wieder so sein wie beim letzten Mal daß es ganz woanders hängt.
    Eigentlich hatte ich, wie gesagt, den gesamten Code zu Anfang des Jahres durchforstet. Bleibt mir wohl nichts anderes übrig, als es nochmal zu tun, vielleicht hab ich ja was übersehen. Aber vielleicht kann mir ja nochmal jemand sagen, worauf ich achten muß: Nicht initialisierte Instanzvariable, nicht-initialisierte Pointer, die dadurch irgendwohin zeigen,... Noch irgendwas oder andere Hinweise?

    Vielen DAnk!



  • Zeig mal, wie du die Instanz deiner Klasse anlegst - ansonsten hast du eigtl scho alles, was mir einfallen würde, aufgezählt^^

    bb



  • Kannst du den Fehler in einem weitergabefähigen Minimalprojekt reduzieren?

    Auch könntest du mal CodeGuard aktivieren.



  • Hier die Klasse (ein Ausschnitt) mit der Instanzvariable, wo der Fehler auftritt:

    class SVeg {
          protected:
          //Instanzvariablen:
          double  itsCover;
          double  itsBiomass; 
          double  itsCoverPreviousYear;
    
          public:
          double  itsOldBiomass; 
          int     itsXCoord, itsYCoord; //Koordinaten im Gitter
          double  itsNewCapac; 
          std::bitset<3> PUWDrought;
    
          public:
          //Konstruktoren und Destruktoren
          SVeg();
          SVeg(double cover, int xCoord, int yCoord);
          virtual ~SVeg();
    
          double getCoverPreviousYear();
          double setCoverPreviousYear(double cover);
    };
    
    SVeg::SVeg(){}
    
    SVeg::SVeg(double cover, int xCoord, int yCoord) : itsBiomass(0), itsOldBiomass(0), itsNewCapac(0.0) {
         itsCover=cover;
         itsXCoord=xCoord;
         itsYCoord=yCoord;
         itsCoverPreviousYear=cover;
         PUWDrought=0;
    }
    
    SVeg::~SVeg(){
    }
    
    double SVeg::getCoverPreviousYear() {
           return itsCoverPreviousYear;
    }
    
    double SVeg::setCoverPreviousYear(double cover) {
           itsCoverPreviousYear=cover;
    }
    

    Im folgenden der aufrufende Code. Die Instanzen von oben stehen in einem Array (cellInfo) drin, und zwar als shr, dwShr, dec oder inc:

    for (int x = 0; x < xsize; x++) {
        for (int y = 0; y < ysize; y++) {
            if (cellInfo[x][y]->shr!=0) cellInfo[x][y]->shr->setCoverPreviousYear(cellInfo[x][y]->shr->getCover());
            if (cellInfo[x][y]->dwShr!=0) cellInfo[x][y]->dwShr->setCoverPreviousYear(cellInfo[x][y]->dwShr->getCover());
            if (cellInfo[x][y]->dec!=0) cellInfo[x][y]->dec->setCoverPreviousYear(cellInfo[x][y]->dec->getCover());
            if (cellInfo[x][y]->inc!=0) cellInfo[x][y]->inc->setCoverPreviousYear(cellInfo[x][y]->inc->getCover());
        }
    }
    

    Und hier beim Aufruf von setCoverPreviousYear() hängt's, nicht unbedingt beim ersten Aufruf, aber schon relativ zu Anfang. Und der Fehler tritt auch auf, wenn ich als Argument statt dem Aufruf von getCover() 0.5 übergebe.

    @audacia:

    Du meinst, einen Ausschnitt vom Code liefern, der alleine läuft und den Fehler enthält?
    Tja, das ist nicht so einfach.
    Mal gucken, ob ihr mir so schon was sagen könnt, ansonsten werde ich das mal mit CodeGuard probieren (der letztes Mal allerdings nichts genutzt hat) und mir nebenher mal überlegen, wie ich den Code am besten einschrumpfen kann.

    Danke!



  • Hat sich erledigt, hab den Fehler gefunden, statt

    double setCoverPreviousYear(double cover);
    

    hätte es

    void setCoverPreviousYear(double cover);
    

    heißen müssen.
    Jetzt läufts. Komisch, mit sowas hab ich nicht gerechnet... Na ja, dann bis zum nächsten Fehler...
    Danke jedenfalls für Eure Mühe!



  • ist nen sicheres zeichen, den compiler zu wechseln, wenn du bei so was nich ma ne warnung erhältst - normalerweise sollte es so gar nen fehler geben...

    bb



  • unskilled schrieb:

    ist nen sicheres zeichen, den compiler zu wechseln, wenn du bei so was nich ma ne warnung erhältst

    Das ist vielmehr ein Indiz, daß du mal auf Warnungen achten solltest. C++Builder emittiert in diesem Fall nicht zu Unrecht W8070.



  • öhmmm,... hab ich tomaten auf den Augen? Warum geht es denn mit void als Rückgabewert anstatt double als einzige Änderung?
    OK, es wird kein Wert zurückgegeben trotz double-return-typ, aber er wird ja auch nciht benutzt beim Aufruf, also ignoriert. Warum stürzt es dann ab?



  • Maxi schrieb:

    Warum stürzt es dann ab?

    Weil undefiniertes Verhalten und so...

    bb



  • was?

    double foo(double x)
    {
      // tu nichts
    }
    
    int main()
    {
      foo(42.42);
    }
    

    ist undefiniertes Verhalten?


Anmelden zum Antworten