connect cause exception triggered (Beginner)



  • hi i'm learning c++ and i don't like library used by my book (use ftlk) so i decided to learn qt (i have seen is widley used).
    so this is my code:

    connect(send,&QPushButton::clicked,[&](){ resultBox->setText(plugin->send_paste(textBox->document()->toPlainText())); });
    

    and this is my error
    c:\users\qt\work\qt\qtbase\src\corelib\tools\qscopedpointer.h:141: error: Exception at 0x6aefda1a, code: 0xc0000005: read access violation at: 0x0, flags=0x0 (first chance)

    what is the cause?



  • most likely either send was not created before calling connect.

    do you have something like send=new QPushButton(/*parent?*/) somewhere before the connect?



  • of course i have this is the complete code:

    void MainWindow::build_tab_from_plugin(Plugin *plugin)
    {
      QWidget* tab = new QWidget();
    
      QVBoxLayout* layout = new QVBoxLayout();
      QPushButton* send = new QPushButton();
      QPlainTextEdit* textBox = new QPlainTextEdit();
      QLineEdit* resultBox = new QLineEdit();
    
      connect(send,&QPushButton::clicked,[&](){ resultBox->setText(plugin->send_paste(textBox->document()->toPlainText())); });
    
      resultBox->setReadOnly(true);
      send->setText("Send paste");
    
      layout->addWidget(send);
      layout->addWidget(textBox);
      layout->addWidget(resultBox);
      tab->setLayout(layout);
    
      ui->tabWidget->addTab(tab,plugin->name());
    
    }
    

    and i benefit from this thread to ask "the objects init in heap store are delete by main window is some way or i have to manually delete them in destructor?"


  • Qt Champions 2016

    @DumaPlusPlus
    Hi,

    read access violation at: 0x0, flags=0x0

    You're dereferencing a null pointer. Look at the stack at the moment of the crash and it will tell you exactly where this is happening.

    the objects init in heap store are delete by main window is some way or i have to manually delete them in destructor?

    Someone has to delete them. If you give them a parent, the parent will do it, if you don't (and you don't) you have to handle that manually.

    Kind regards.



  • when you click the button, plugin in the lambda will be a dangling pointer. In debug mode some compilers set dangling pointers to NULL and this triggers your error.
    Bottom line: you are misusing the lambda

    about the delete question, when you call layout->addWidget(); the layout will take care of deleting the widgets see http://doc.qt.io/qt-5/qlayout.html#addItem



  • it's strange i init them in heap store and acces them with a static list:
    in mainwindow.cpp's constructor

     for(Plugin* p : PluginCollection::get_plugins())
        {
          build_tab_from_plugin(p);
        }
    

    plugincollection.h

    namespace PluginCollection
    {
      QList<Plugin *> get_plugins()
      {
        static QList<Plugin*> list {new PastebinPlugin() };
        return list;
      }
    }
    

    should static list stay in memory (as well as allocated obj) until application closing?


  • Moderators

    @DumaPlusPlus You're passing references to local variables [&] which only exist while MainWindow::build_tab_from_plugin is being executed. Since everything you use in the lambda are pointers you can pass by value [=]. Is plugin a valid pointer?



  • EDIT: I WAS WRONG

    no matter how you pass thos variables [&] or [=]. when the lambda gets called all those pointers will be junk so it won't work


  • Qt Champions 2016

    @VRonin

    when the lambda gets called all those pointers will be junk

    Why? I think @jsulm is correct here.



  • EDIT: I WAS WRONG

    when You call build_tab_from_plugin() all the pointers are valid and fine, then the function terminates and all pointers go out of scope. when the button is pressed, the code goes into the lambda (imagine a goto), the environment of build_tab_from_plugin is recreated but you don't know what the pointers point to right now. the lambda won't save the value of any of the pointers in its body uppon declaration



  • thanks to all.
    @jsulm resolves my problem but now i'm bit confused when do i connect SIGNAL with lambda this isn't stored somewhere? and reference used in lambda isn't an alias to a pointer (something that stay in memoery untile delete operator is called) ?


  • Qt Champions 2016

    @VRonin said:

    the lambda won't save the value of any of the pointers in its body uppon declaration

    Sure about this? As far as I know C++11 (which isn't so well) a pointer is an automatic storage variable and is copy-captured by [=] as any other auto-storage variable.

    the code goes into the lambda (imagine a goto), the environment of build_tab_from_plugin is recreated

    This is very wrong way of thinking about a lambda, sorry for saying. A lambda is a typical functor (and is implemented as such).


  • Moderators

    @DumaPlusPlus If you use references then then "point" to the variable. In your case they point to local variables. These local variables disappear as soon as the method finishes, so the "pointers" to them are not valid anymore - because they do not exist anymore.


  • Moderators

    @VRonin Sorry, but you're wrong. You can easily test this: using [&] will crash, using [=] works just fine.



  • @jsulm I'm really confused now as I tested it and this code works 100% fine, even with [&]. how can it be?!

    #include <QCoreApplication>
    #include<QDebug>
    #include <QTimer>
    
    
    int main(int argc, char *argv[]) {
        QCoreApplication appl(argc,argv);
        QTimer mainTimer;
        mainTimer.setSingleShot(true);
        {
            QString* myString=nullptr;
            myString=new QString("A Message");
            QObject::connect(&mainTimer,&QTimer::timeout,[&](){qDebug() << *myString;});
            QObject::connect(&mainTimer,&QTimer::timeout,[=](){qDebug() << *myString;});
            // Memory leak!
        }
    
        mainTimer.start(100);
        return appl.exec();
    }
    
    

    EDIT:
    Using MSVC2013 on Windows


  • Qt Champions 2016

    @VRonin said:

    QObject::connect(&mainTimer,&QTimer::timeout,[&](){qDebug() << *myString;});
    

    What about:

    QObject::connect(&mainTimer,&QTimer::timeout,[&](){myString = nullptr;});
    

    You're capturing QString*, so you'd end up with: QString*& but you don't modify the string pointer, rather you dereference the object it's pointing to, so you'd try to output a QString & with QDebug. Also probably your compiler somewhat lax. :)

    PS.
    Well that's really disturbing ... I don't get any errors either. The memory will silently be overwritten. (g++ on Linux)



  • second test:

    #include <QCoreApplication>
    #include <QDebug>
    #include <QTimer>
    #include <QPointer>
    
    int main(int argc, char *argv[]) {
        QCoreApplication appl(argc,argv);
        QTimer mainTimer;
        mainTimer.setSingleShot(true);
        {
            QPointer<QObject> mybj;
            mybj =new QObject();
            mybj->setObjectName("A Message");
            QObject::connect(&mainTimer,&QTimer::timeout,[&](){qDebug() << mybj->objectName(); mybj->setObjectName("Foo"); qDebug() << mybj->objectName();});
            QObject::connect(&mainTimer,&QTimer::timeout,[=](){qDebug() << mybj->objectName(); mybj->setObjectName("Bar"); qDebug() << mybj->objectName();});
            // Memory leak!
        }
        {
            QString testString("Occuppy Stack");
        }
        mainTimer.start(100);
        return appl.exec();
    }
    
    

    Still working correctly. Notice how the first output of the [=] lambda is Foo. HOW?!



  • @VRonin said:

    second test:

            QObject::connect(&mainTimer,&QTimer::timeout,[&](){qDebug() << mybj->objectName(); mybj->setObjectName("Foo"); qDebug() << mybj->objectName();});
            QObject::connect(&mainTimer,&QTimer::timeout,[=](){qDebug() << mybj->objectName(); mybj->setObjectName("Bar"); qDebug() << mybj->objectName();});
    
    
    Still working correctly. Notice how the first output of the [=] lambda is Foo. HOW?!
    

    should be that?
    passing by value copy the pointer so you point to objname with modified name...right?



  • @DumaPlusPlus The first lambda should never be executed at the creation of the second one. then when the timer times out I was expecting the first to crash or operate on invalid memory and the second to print

    A Message
    Bar
    

    While it looks like the lambda with [&] behaves exactly as the one with [=]


  • Qt Champions 2016

    @VRonin

    If I haven't missed anything. my g++ doesn't open a new stack frame when it sees: { }. So in your examples (which I used) all is flat, thus myString is in main()'s stack frame, which means it doesn't go out of scope (i.e. it's not pop-ed from the stack), which ultimately means that the lambda capture is valid.

    Here's what I have for main() from your QString test case:

    # Sets up main()'s stack
    0x400fc2                   55                                push   %rbp
    0x400fc3  <+0x0001>        48 89 e5                          mov    %rsp,%rbp
    ...
    0x400fcf  <+0x000d>        48 83 ec 78                       sub    $0x78,%rsp
    ...
    # mainTimer.setSingleShot(true);
    0x401010  <+0x004e>        48 8d 45 80                       lea    -0x80(%rbp),%rax
    0x401014  <+0x0052>        be 01 00 00 00                    mov    $0x1,%esi
    0x401019  <+0x0057>        48 89 c7                          mov    %rax,%rdi
    0x40101c  <+0x005a>        e8 59 08 00 00                    callq  0x40187a <QTimer::setSingleShot(bool)>
    # QString * myString = nullptr;
    0x401021  <+0x005f>        48 c7 85 78 ff ff ff 00 00 00 00  movq   $0x0,-0x88(%rbp)
    # No stack frame was opened as one'd expect from a block
    ...
    # main()'s stack's being unwound
    0x40113c  <+0x017a>        48 83 c4 78                       add    $0x78,%rsp
    ...
    0x401149  <+0x0187>        5d                                pop    %rbp
    # And that was all folks, thanks for playing
    0x40114a  <+0x0188>        c3                                retq         
    

    As for the lambda, it doesn't make any checks. It just stores the captured address (the reference) and ultimately dereferences it when it's executed:

    ...
    # qDebug() << *myString;
    0x400ec3  <+0x000d>        48 8b 45 b8           mov    -0x48(%rbp),%rax    # Load QString *& from the base pointer
    0x400ec7  <+0x0011>        48 8b 00              mov    (%rax),%rax         # Dereference once (strip &)
    0x400eca  <+0x0014>        48 8b 18              mov    (%rax),%rbx         # Dereference second time i.e. (*myString)
    

    So I hope this explains how and why.

    Kind regards.



  • Thanks @kshegunov now it make sense, it was just the compiler (I use MSVC btw) optimizing.
    This behaves as expected.

    #include <QCoreApplication>
    #include<QDebug>
    #include <QTimer>
    
    void makeConnections(QTimer* mainTimer ){
        QString* myString=nullptr;
        myString=new QString("A Message");
        QObject::connect(mainTimer,&QTimer::timeout,[&](){qDebug() << *myString;});
        QObject::connect(mainTimer,&QTimer::timeout,[=](){qDebug() << *myString;});
    }
    
    int main(int argc, char *argv[]) {
        QCoreApplication appl(argc,argv);
        QTimer mainTimer;
        mainTimer.setSingleShot(true);
        makeConnections(&mainTimer);
    
        mainTimer.start(100);
        return appl.exec();
    }
    
    

    I marked my previous post where I was wrong and the final answer to the topic is use [=] in the lambda instead of [&]


  • Qt Champions 2016

    @VRonin

    Thanks @kshegunov now it make sense, it was just the compiler (I use MSVC btw) optimizing.

    No problem. Yes the compiler was an issue apparently, although that's some strange optimization made. Especially if you take into account we're running in debug mode, two different compilers no less. But even in release mode I'd venture to say one doesn't expect a block to just be ignored ... at least I don't.

    This behaves as expected.

    Meaning it crashes at the appropriate place? :)



  • @kshegunov said:

    Meaning it crashes at the appropriate place? :)

    Even a crash sometimes is expected behaviour ;)



  • wow very good thread i wish i will be professional like you


  • Qt Champions 2016

    @DumaPlusPlus
    It's only matter of experience, so just be patient. And funnily enough currently I don't work as a programmer, so I'm actually falling in the category of amateur, or at least hobbyist. ;)

    @jsulm
    Out of curiosity, what compiler are you running?


  • Moderators

    @kshegunov MinGW 5.3.0 32bit on Windows 7.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.