Solved connect cause exception triggered (Beginner)
-
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 [=]
-
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, thusmyString
is inmain()
'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 yourQString
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 [&]
-
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
-
@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? -
@kshegunov MinGW 5.3.0 32bit on Windows 7.