Exception Problem



  • Hallo zusammen,

    habe einen Parser geschrieben. Wenn das Format nicht
    passt, wird eine Exception geworfen.

    class ParserException: public exception {
    public:
        const char *message;
        int line;
        int col;
    
        ParserException(char *msg, int iline, int icol){
            line = iline;
            col = icol;
            message = msg;
        }
        ParserException(string msg, int iline, int icol) {
            line = iline;
            col = icol;
            message = msg.c_str();
        }
    
        virtual const char* what() const throw()
        {
            stringstream msg;
            msg << message << endl << endl;
            // wenn eine -1 angegeben wird, konnte die Zeile nicht bestimmt werden
            if (line != -1){
                msg << "Line: " << line << endl;
                // wenn eine -1 angegeben wird, konnte die Spalte nicht bestimmt werden
                // es macht auch wenig sinn die Spalte anzugeben, wenn keine Zeile vorhanden ist.
                if (col != -1 ) {
                    msg << "Column: " << col << endl;
                }
            }
            cout << "IN EXCEPTION:" << endl << msg.str() << endl;
            return msg.str().c_str();
        }
    };
    

    Der cout, der mit "IN EXCEPTION:" beginnt, gibt immer den richtigen Text aus. An der Stelle, an der ich das ganze auffange, kommt aber nur zu ca. 40% der Text. Meist bekomme ich einen leeren String, selten eine ganz seltsame Zeichenfolge.

    Das ganze will ich als Messagebox in qt ausgeben. Habe aber auch einen cout dvor gesetzt, der das gleiche Verhalten aufweist.

    } catch (ParserException &e) {
        cout << "cout ----" << endl << e.what() << endl << "-----" << endl;
        QString error = e.what();
        qDebug()<< "IN textedit-----" << endl << error << endl << "-----";
        QMessageBox::warning(this, "Warning", error);
        return false;
    }
    

    Mich wundert das unterschiedliche Verhalten. Habe aber auch noch nciht viel mit exceptions gearbeitet.



  • Das Problem ist folgendes: die what()-Funktion verlassen wird, wird der stringstream und der temporäre string, den du mit str() erzeugt hast, zerstört. std::string::c_str() liefert aber einen Zeiger auf ein internes char-Array des strings. Der hat aber bei seiner Zerstörung diesen internen Speicher schon wieder freigegeben, so dass der const char*, den du zurückgibst, auf Speicher zeigt, der dir garnicht mehr gehört und ggf. schon von anderen Objekten belegt wird.
    Was du da siehst ist ein typischer Fall von undefiniertem Verhalten.
    Das Selbe gilt für beide Konstruktoren der Exception. Wenn die exception geworfen wird, wird vermutlich der Speicher, auf den der char* des ersten Ctors zeigt, beim Durchrauschen freigegeben. Der Speicher des std::string wird schon im Ctor freigegeben. Wenn du später what() aufrufst, bentutzt du den internen char*, der irgendwo ins Nirvana zeigt. Insofern ists schon verwunderlich, wenn du tatsächlich immer die richtige Nachricht bei IN EXCEPTION bekommst. Ich vermute mal, dass du der exception immer ein stringliteral übergeben hast, in dem Fall geht das IN EXCEPTION noch, weil der char-Pointer auf das Literal zeigt.



  • Ich Übergebe in der Methode in der ich das teste wirklich immer einen string.

    Aber wie kann ich das sonst lösen? Habe versucht einen string als Attribut zu verwenden, in dem ich dann die Ausgabe speichere. Leider wird das direkt zu const und ich kann ihn nicht verwenden.

    Was wohl gehen könnte wenn ich in what einen string pointer anlege und mit new einen string erstelle, der auf dem heap landet. Nur kann ich den dann nicht mehr löschen.

    Kleine Hilfestellung wäre gut, Danke 🙂



  • Gibt verschiedene Möglichkeiten, aber fast alles wird darauf hinauslaufen, das du für deinen string oder char* selbst speicher anlegen musst (entweder direkt oder über einen container). Kannst das ganze bei mit new geholtem Speicher ja wieder im d-tor freigeben.



  • class ParserException : public exception {
    
        std::string message;
    
    public:
    
        ParserException(string const & msg, int iline, int icol) 
        { 
            std::ostringstream formatter;
            formatter << msg << "\n\n";
            if (iline != -1)
            {
                formatter << "Line: " << iline << '\n';
                if (icol != -1 ) 
                {
                    formatter << "Column: " << icol << '\n';
                }
            }
            message = formatter.str();
        }
    
        virtual const char* what() const throw()
        {
            return message.c_str();
        }
    };
    


  • Alternativ kannst du natürlich statt das Rad neu zu erfinden auch einfach von std::runtime_error ableiten, der hat einen Ctor, der einen std::string erwartet und regelt den ganzen Krempel mit der Speicherverwaltung für den what()-string selbst.



  • Ok danke.

    Denke ich werd den string einfach im Ctor zusammensetzten, wie Tachyon geschrieben hat.


Anmelden zum Antworten