Qt5: Segfault bei widget_list->add_items(...)



  • Was mich auch etwas empört, ist wenn ich folgendes schreibe:

    void MainWindow::add_files(){
        QStringList list = QFileDialog::getOpenFileNames(this, "Select one or more files", QDir::homePath());
        if(list.isEmpty() == false){
            files_list = new QWidgetList(this);// <=== Einfach nur zum Test halber - Debugger sagt Segfault
            files_list->addItems(std::move(list));
        }
    }
    

    Schon gleich wenn ich den Speicher "nochmal" allokieren möchte enteht in der Zeile mit new ein Segfault.

    What the hell is going on? :0



  • *QListWidget



  • Zweifach empört mich

    exited with code 0
    


  • Benutzername_ schrieb:

    Mechanics schrieb:

    Ich würde spontan sagen, std::move ist der Fehler, lass den Weg.

    ohne std::move() schlägt es auch fehl.
    Warum kein auto? Ist doch so schön kurz 🙂

    Es hilft überhaupt nichts, den Datentyp zu verbergen. Man überfliegt den Quellcode öfter, als man ihn schreibt. Und da weiß man vielleicht nicht sofort auswendig, was eine bestimmte Funktion zurückgibt. Ich finde, auto ist genauso eine Krankheit wie das var in C#. Es hilft bei komplexen Templatekonstrukten, wo man den konkreten Typen vielleicht gar nicht angeben kann, aber wo es das gibt meint plötzlich jeder, er muss es überall hinschreiben.

    Dann wird dein MainWindow ungültig sein.



  • Ungültig in welchem Sinne?

    Ich erstelle in der main() lediglich ein MainWindow auf dem Heap, wobei dieses vom Heap freigegeben wird, wenn das Fenster schließt. Der Segfault entsteht trotzdem.
    Auf dem Stack die gleiche Leier.

    #include <QtWidgets/QApplication>
    #include "main_window.hpp"
    
    int main(int argc, char** argv){
        QApplication backup_maker(argc, argv);
    
        MainWindow* main_window = new MainWindow;
        main_window->setAttribute(Qt::WA_DeleteOnClose);
    
        main_window->setWindowTitle("Backup Maker");
        main_window->resize(500, 300);
    
        main_window->showMaximized();
    
        return backup_maker.exec();
    }
    


  • Auf den ersten Blick seh ich keinen Fehler. Debuggs halt durch, dann müsstest du sofort sehen, was nicht passt.



  • Nach genauerem debuggen ist mir aufgefallen, dass sobald die Funktion add_files() aufgerufen wird, der this-Pointer auf 0 steht. Aber wo der jetzt wieder auf 0 gesetzt wird ist mir ungeklar (bin selbst noch recht neu bei Qt). Ich dachte nur die Childs von einem QObject werden automatisch vom Heap freigegeben, wobei das bei mir ja nicht der Fall ist. Viel mehr Code außer die Klassendeklaration, und den Code, den ich mit ... versteckt hab ich halt auch nicht zu zeigen.

    Klassendeklaration
    Der komplette Konstruktor
    main.cpp: Siehe oben.

    Ich seh einfach zum Kreischen keinen Fehler.


  • Mod

    Unter Umständen captured [&] nicht this. [this,&] könnte dein Problem also beheben.



  • phlox81 schrieb:

    Unter Umständen captured [&] nicht this. [this,&] könnte dein Problem also beheben.

    Eben vergeblichst versucht.
    Und auch wenn this nicht captured werden würde, so müsste dann sowieso eigentlich die Fehlermeldung "'this' was not captured for this lambda function" auftreten, was jedoch nicht passiert.



  • Ich habe das Problem nun (bedingt) gelöst.

    Meiner Meinung nach liegt es an diesen Zeilen:

    template<class Function, class... Arguments>
        void add_action(const QString& name, Function&& function, Arguments&&... arguments){
            action = new QAction(name, this);
            menu->addAction(action);
    
            connect(action, &QAction::triggered, [&function](Arguments&&... arguments){
                std::forward<Function>(function)(std::forward<Arguments>(arguments)...);
            });
        }
    

    Denn wenn ich die alte connect-Funktionen benutze (mit SIGNAL() und SLOT()) funktioniert es komischerweise einwandfrei. Warum? Ist mir derzeit noch ein Rätsel.



  • Nach einigem rumspielen ist mir nun bewusst, dass es nicht nur zwanghaft mit SIGNAL() und SLOT() funktioniert.

    Es funktioniert tatsächlich auch mit den neuen connect-Funktionen, nur ein bisschen anders.

    Statt folgendes zu tun:

    add_action("Add Files", [this]{ add_files(); }); // oder mit std::bind()
    

    habe ich nun die Funktion add_action(const QString&, Function&&, Arguments&&...) auf add_action(const QString&) reduzieren lassen, und dann per Hand alle connect-Funktionen geschrieben. Und siehe da! Es funktioniert.

    Wobei mir jedoch immer noch nicht bewusst ist, warum ich der Funktion add_action nicht einfach die auf Signal aufzurufenden Funktionen übergeben kann, und somit nicht mehr jede einzelne connect-Funktion selber schreiben muss. Wenn ich dies jedoch tu - egal wie ich mich anstelle - ist der this-Pointer bei Aufruf der Funktion auf 0 und das Programm geht mir somit durch die Lappen. Gibt es vielleicht was zum Thema Funktionszeiger was mir bisher noch nicht bewusst ist, wobei dies dazu führt, dass das Programm abstürzt?



  • Das Problem ist nun (durch rumprobieren) gelöst.

    Folgendes funktioniert:

    std::function<void(void)> func = std::bind(std::forward<Function>(function), std::forward<Arguments>(arguments)...);
            connect(action, &QAction::triggered, func);
    

    Dies funktioniert jedoch nicht:

    connect(action, &QAction::triggered, std::bind(std::forward<Function>(function), std::forward<Arguments>(arguments)...));
    

    Warum letzteres nicht funktioniert ist mir immer noch unklar.



  • Das ist keine Qt, sondern eine C++11 Frage. Stell sie im entsprechenden Forum, dann werden sich das mehr Leute anschauen, die Erfahrung damit haben.


Anmelden zum Antworten