Solved Why did I get a 'Debug Assertion Failed' in this QGridLayout project?
-
I was trying out
QGridLayout
, and I wanted to see if I could place a grid layout within another grid layout. I made three pushbuttons, and placed 2 of them in asmallGrid
. I added thesmallGrid
to thebigGrid
, along with the last pushbutton I initialized. The program ran, but on exit, I got a window with an error that included this:|||||
Microsoft Vistual C++ Runtime Library
Debug Assertion Failed!
...
Expression: _CrtlsValidHeapPointer(block)
|||||Why did I get this error? The program still ran. Did I forget to add something when I made my
QGridLayout
instances?#include <QtWidgets> #include <QPushButton> int main(int argc, char *argv[]) { QApplication app(argc, argv); QWidget window; window.resize(320, 340); window.show(); QPushButton a,b,c; a.setText("A"); b.setText("B"); c.setText("C"); a.show(); b.show(); c.show(); QGridLayout smallGrid; smallGrid.addWidget(&a,0,0); smallGrid.addWidget(&b,1,0); QGridLayout bigGrid; bigGrid.addLayout(&smallGrid,0,0); bigGrid.addWidget(&c,0,1); window.setLayout(&bigGrid); return app.exec(); }
-
:::Pure Guessing:::
Hi
smallGrid.addWidget(&a,0,0); This owns the widget. The layout will delete the Widget.
QPushButton a,b,c; // this will be deleted when running out of scope.
So a,b,c might be deleted twice. From layout and then from scope.
You can fix this by newing the buttons or by using a widget and not main for the code.
-
Oh, ok. I didn't know widgets were deleted after addWidget. I tried placing all my code in a subclass of QWidget in a "header.h", then I put
TestWidget widget; window.setLayout(&(widget.bigGrid));
in my main.cpp. It didn't work, still got the debug error. Was that what you meant by "using a widget"? Here's my class definition for TestWidget that I used. Also, what did you mean by "newing the buttons"? QPushButton doesn't seem to have a "renew" function with it.class TestWidget: public QWidget { Q_OBJECT public: TestWidget(QWidget *parent = 0 ): QWidget(parent) { setup(); } QPushButton a,b,c; QGridLayout smallGrid; QGridLayout bigGrid; void setup() { a.setText("Test"); smallGrid.addWidget(&a,0,0); smallGrid.addWidget(&b,1,0); bigGrid.addLayout(&smallGrid,0,0); bigGrid.addWidget(&c,0,1); } };
-
Hi
Yes moving to widget seems much cleaner :) Good work.- Also, what did you mean by "newing the buttons"
Sorry. badly told.
What I mean is
QPushButton *a = new QPushButton ();
When you new it,
it means that it would NOT be deleted by scope, only the layout / parent/owner.If you are not aware of Qt parent child ownership system, you best read up on it to avoid huge "ohhhh" experiences.
http://doc.qt.io/qt-5/objecttrees.htmlBasically it means when you give it parent
QPushButton *a = new QPushButton (this); // this is parent
or add to layout
That object now owns it and will delete it for you. -
Oh ok, I'll look more into the link. It works now, both in
main
and inTestWidget
class. Allocating on the stack has worked for me until this case, so I'll start allocating on the heap with "new". Thanks! -
@DragonautX
There is nothing wrong with using the stack, ( at all)
but one must understand the Owner system as not to crash.
So often "new" the widgets to avoid deletion conflicts.
But there are many cases where stack is pretty fine and issue-less.Like showing a dialog
void Ask() {
MyDialog Dia;
Dia.exec(); // blocking
...
} -
Oh ok, so most of the time I can choose between either stack or heap. Looking at your link, in this case I guess the order of the widget initializations is important, but using "new" and the heap instead of the stack allows for constructors/destructors to be called in any order, allowing my project to run without errors.
-
@DragonautX
Yes, both stack and heap work
but as you have seen , the auto delete system does require you to think
slightly more about it when using the stack.