Programm stürzt ab beim Zuweisen einer Variable



  • Hallo,

    das Folgende ist mir ziemlich peinlich: Ich möchte eine Variable einer Klasse zuweisen, jedoch stürzt dadurch mein Programm ab. Wenn ich die Zeile rausnehme, funktioniert es und wenn ich vor und nach der Zuweisung eine MessageBox anzeige, wird nur eine angezeigt. Das muss ja bedeuten, dass ich die Variable nicht zuweisen kann.

    Der Typ der Variable ist ein Funktionszeiger

    typedef std::function<void (UIButton*)> OnClickCallback;
    

    mit dessen Hilfe ich eine Funktion aufrufen möchte, sobald ein Ereignis eintritt. D.h. in meiner Klasse habe ich eine public Variable, der ich beim Erzeugen meines Objekts eine Callback Funktion zuweise. Das ganze sieht dann so aus:

    UIWindow* window = new UIWindow(IDD_DLG1);
    UIButton* btn1 = (UIButton*) window->getChild(IDC_SAVE);
    
    if (btn1 != NULL) {
    	btn1->onClick = btn1_Click; // BIG CRASH
    	MessageBox(NULL, "Button found", "", MB_OK); // WIRD NICHT MEHR AUSGEFÜHRT
    }
    window->show();
    

    Das Programm gibt beim Absturz den Fehlercode 0xc000000005 (Access Violation) zurück. Aber was habe ich bitteschön falsch gemacht?

    Danke im Voraus


  • Mod

    Nun, wenn man einen Absturz zwei Zeilen nach einen reinterpret_cast hat (mit dem man dem Compiler sagt, dass er die Schnauze halten soll, selbst wenn er meint, dass da etwas nicht passt), noch dazu direkt bei Zugriff auf das gecastete Objekt, dann war der Compiler wohl doch schlauer als der Programmierer.

    Da ich keine Ahnung habe, was die ganzen Sachen überhaupt sind, kann ich natürlich nicht 100% sagen, ob es das wirklich ist oder wie es richtig wäre, aber höchst verdächtig ist es schon.



  • Änderte ich Zeile 2 meines vorherigen Code-Snippets zu

    UIButton* btn1 = reinterpret_cast<UIButton*> (window->getChild(IDC_SAVE));
    

    bleibt der Fehler. Außerdem habe ich Zugriff auf das Objekt, weil beispielsweise die abgeleitete Funktion btn1->setText(...) einwandfrei funktioniert.

    EDIT:

    Wie sich gerade herausgestellt hat, lag es an der Typdefinition von OnClickCallback 😢 Benutze ich stattdessen nämlich

    typedef void (*OnClickCallback)(UIButton*);
    

    , stürzt das Programm nicht ab.
    Wieso funktioniert das nicht mit std::function<...> ? Vorher hats doch auch funktioniert 😕 😕 😕



  • Der Schuldige dürfte Rainer Zufall heißen.

    Ohne zu wissen, womit du da arbeitest, ist deine Frage nicht zu beantworten. Vielleicht betreibt das Framework Fensterinitialisierung in zwei Schritten und du hast den zweiten vergessen, greifst also auf uninitialisierte Daten zu. Vielleicht hast du dir den Heap schon vorher zerschossen. Schnapp dir einen Debugger und kuck nach.


  • Mod

    DerCoder schrieb:

    Änderte ich Zeile 2 meines vorherigen Code-Snippets zu

    UIButton* btn1 = reinterpret_cast<UIButton*> (window->getChild(IDC_SAVE));
    

    bleibt der Fehler. Außerdem habe ich Zugriff auf das Objekt, weil beispielsweise die abgeleitete Funktion btn1->setText(...) einwandfrei funktioniert.

    😕 Eben! Wenn du da einen reinterpret_cast benutzt, egal ob in Form eines C-Casts (der eben auch ein reinterpret_cast sein kann) oder als richtiger C++-Cast, dann sagst du, dass du schlauer bist als die Typprüfung des Compilers. Und dann solltest du damit gefälligst auch richtig liegen. Was hier anscheinend nicht der Fall war.

    Wieso funktioniert das nicht mit std::function<...> ?

    Weil ein Zeiger auf std::function eben kein reinterpretierter Funktionszeiger ist, genau davor hätte dich der Compiler sicher warnen wollen.

    Im Moment ist mir aber auch nicht klar, was für Typen welche Funktion zurück gibt, was deine Typedefs sind und überhaupt. Kannst du mal vollständig und übersichtlich angeben, was was ist? Dann könnte man dir viel genauer sagen, wie es richtig geht, sowohl mit std::function als auch ohne.



  • Das ist meine erste kleine selbstgebackene GUI-Klasse. ÖÖhm, wenn du willst lad ich die Klassen hoch und schicke Links.

    Jedenfalls hat es, als ich anstelle eines UIButton ein UIElement (was die Basisklasse von UIButton ist) benutzt habe, wo auch mein onClick pointer drinne war, NOCH FUNKTIONIERT!!

    http://dercoder.shafted.de/class/UIButton.hpp
    http://dercoder.shafted.de/class/UIElement.hpp
    http://dercoder.shafted.de/class/UIWindow.hpp



  • Okay, das ist nun wirklich mysteriös: Wenn ich

    OnClickCallback onClick;
    

    in meiner UIElement (der Basisklasse) deklariere, FUNKTIONIERT ES! Wenn ich allerdings die Unterklasse UIButton nehme, stürzt das Programm ab. Warum, weiß ich nicht.

    Habs jetzt jedenfalls gelöst – entschuldigt wegen eben. War ein wenig gestresst von diesem Sch***


  • Mod

    FUNKTIONIERT ES!

    Ist ja schön für dich, wenn du jedoch tatsächlich Antworten auf

    Warum, weiß ich nicht.

    haben möchtest, musst du schon etwas weniger geheimnisvoll sein. Denk dran ,wir kennen weder dein Programm, noch dein Framework, noch deine Ideen, noch was du vor hast, noch was du gemacht hast, usw. Dann ist ein

    Wenn ich allerdings die Unterklasse UIButton nehme

    einfach viel zu wenig als Problembeschreibung. Das ist wie "Herr Automechaniker, wenn ich die Hauptstraße entlang fahre, tut was nicht".



  • Naja, ich hatte ja beschrieben, was bei mir Sache ist, den Fehlercode angegeben und außerdem die Klassen auf meinen FTP-Server geladen.

    Was soll ich denn noch tun?



  • seldon schrieb:

    Schnapp dir einen Debugger und kuck nach.


  • Mod

    DerCoder schrieb:

    und außerdem die Klassen auf meinen FTP-Server geladen.

    Ahh, das ist gut, ich hatte deinen edit weiter oben nicht gesehen.



  • Selbst wenn ich mich mit einem Debugger auskennen würde, wäre mir damit nicht viel geholfen. Warum sollte denn das Zuweisen einer Variable in der Basisklasse funktionieren und das Zuweisen einer Variable des gleichen Types in einer Unterklasse mit einer Access Violation enden?


  • Mod

    DerCoder schrieb:

    Selbst wenn ich mich mit einem Debugger auskennen würde, wäre mir damit nicht viel geholfen.

    Der Debugger gilt als wichtigstes Werkzeug des Programmierers. Jetzt wäre doch eine gute Gelegenheit, sich damit mal näher zu beschäftigen 🙂

    Zuweisen einer Variable des gleichen Types in einer Unterklasse mit einer Access Violation enden?

    Weil du irgendwo undefiniertes Verhalten erzeugst. Wie schon gesagt sind die vielen reinterpret_casts in deinem Programm ein fast sicheres Zeichen, dass da irgendetwas faul ist. Compiler haben nämlich meistens Recht. Besonders wenn du selber noch unerfahren bist, solltest du eher dem Compiler vertrauen, als dir selber.



  • DerCoder schrieb:

    Selbst wenn ich mich mit einem Debugger auskennen würde, wäre mir damit nicht viel geholfen. Warum sollte denn das Zuweisen einer Variable in der Basisklasse funktionieren und das Zuweisen einer Variable des gleichen Types in einer Unterklasse mit einer Access Violation enden?

    Weil das von getChild gelieferte UIElement gar kein UIButton ist? Ich würde mal ein dynamic_cast probieren. Wenn der 0 liefert, war es kein UIButton.

    Im Debugger könnte man das vermutlich auch direkt sehen.



  • Nein, manni66, das passt alles. Ich kann ja auch Memberfunktionen vom UIButton aufrufen, ohne dass es Probleme gibt. Nur das Zuweisen geht nicht.

    Verschiebe ich allerdings die Zeile

    std::function<void (UIButton*> onClick;
    

    aus der UIButton.hpp in die UIElement.hpp, klappt es. Das Programm stürzt nicht ab. Anscheinend habe ich keinen Zugriff auf die über die Zuweisung übergebene Funktion in meiner Unterklasse.

    Aber wie gesagt, ich kann dazu nichts sagen, weil ich mir das absolut nicht erklären kann.



  • Moment, ich glaube, du hast die Fehlermeldung falsch verstanden.
    Das Access Violation bezieht sich nicht auf Konstrukte, die C++ bereitstellt, wie die Schutzstufen protected und private bei Klassen, sondern auf Zugriffe auf den Arbeitsspeicher. Das Auftreten der Meldung heißt, dass du auf Speicher zugegriffen hast, auf den du nicht zugreifen durftest. Beispiel:

    #include <iostream>
    #include <ostream>
    
    int main()
    {
      int* Zeiger_Irgendwohin = reinterpret_cast<int*>(0xBADFA15E);
        //Hier passiert noch nichts, aber das Übel ist nah
        //Vielleicht steht hier auch noch ein Haufen Zeug
      int WirdNix = *Zeiger_Irgendwohin;
        //Hier wird dann eine Access Violation, eine Speicherzugriffsverletzung,
        //vom BS ausgelöst (bei allen modernen, Nischensysteme ausgenommen ;) )
      std::cout << WirdNix << std::endl;
        //Ohne die Ausgabe wurde der Zugriff beim Test auf Codepad rausoptimiert
    }
    

    Dem C++-Compiler ist es erstmal völlig egal, dass da dem Zeiger einfach irgendeine erfundene Konstante zugewiesen wird (der Typ wird ja explizit geändert), schließlich kompillierst du vielleicht für irgendeine Embedded-Architektur, wo du sicher an diese Stelle schreiben kannst.



  • DerCoder schrieb:

    Nein, manni66, das passt alles. Ich kann ja auch Memberfunktionen vom UIButton aufrufen, ohne dass es Probleme gibt. Nur das Zuweisen geht nicht.

    Ja und?



  • manni66 schrieb:

    DerCoder schrieb:

    Nein, manni66, das passt alles. Ich kann ja auch Memberfunktionen vom UIButton aufrufen, ohne dass es Probleme gibt. Nur das Zuweisen geht nicht.

    Ja und?

    Ja, das heißt doch, dass mein Zeiger geht 😃 Außerdem muss ich static_cast<> nehmen und nicht dynamic_cast<>, weil ich ja nur die Zeiger auf die Klassenobjekte ableite.

    Fast2_unreg schrieb:

    Moment, ich glaube, du hast die Fehlermeldung falsch verstanden.

    Nein, das glaube ich nicht. Würde ich auf eine als private deklarierte Variable zugreifen wollen, schreitet der Compiler schon zur Kompilierungszeit ein.

    Folgendes hat sich herauskristallisiert:

    // UIElement.hpp
    
    class UIButton;
    typedef std::function<void (UIButton*)> OnClickCallback;
    
    class UIElement {
        private:
        public:
            OnClickCallback onClick;
    }
    
    ...
    // main.cpp
    window->getChild(IDC_SAVE)->onClick = MeineCallbackFunktion; // FUNKTIONIERT! Keine Access Violation
    
    // UIButton.hpp
    
    typedef std::function<void (UIButton*)> OnClickCallback;
    
    class UIButton : public UIElement {
        private:
        public:
            OnClickCallback onClick;
    }
    
    ...
    // main.cpp
    ((UIButton*) window->getChild(IDC_SAVE))->onClick = MeineCallbackFunktion; // FUNKTIONIERT NICHT! 0xc000000005
    

  • Mod

    Da ist ja immer noch reinterpret_cast drin, wundert dich da ein Absturz? Wie erzeugst du denn das "child"? Vermutlich ist das gar kein UIButton.



  • DerCoder schrieb:

    manni66 schrieb:

    DerCoder schrieb:

    Nein, manni66, das passt alles. Ich kann ja auch Memberfunktionen vom UIButton aufrufen, ohne dass es Probleme gibt. Nur das Zuweisen geht nicht.

    Ja und?

    Ja, das heißt doch, dass mein Zeiger geht

    Nein

    DerCoder schrieb:

    Außerdem muss ich static_cast<> nehmen und nicht dynamic_cast<>, weil ich ja nur die Zeiger auf die Klassenobjekte ableite.

    Aha, wie leitet man denn Zeiger ab?


Log in to reply