January 4, 2011

jandin jandin
Lab Rat
3 posts

The difference between Qwidget object and pointer

Page  
1

  1. #include <QtGui>
  2. #include "mainwindow.h"
  3.  
  4. int main(int argv, char **args)
  5. {
  6.     QApplication app(argv, args);
  7.     QTextEdit textEdit;
  8.     QVBoxLayout layout;
  9.     layout.addWidget(&textEdit);
  10.  
  11. //    1.If I use the object,I will get an error whe I quit the application.
  12. //    Debug it,I get a signal SIGSEGV which means Segmentation fault
  13.     QWidget window;
  14.     window.setLayout(&layout);
  15.     window.show();
  16. //     2.But if I use the poniter ,it is ok.
  17. //     QWidget *window=new QWidget;
  18. //     window->setLayout(&layout);
  19. //     window->show();
  20.     return app.exec();
  21. }
  22.  
  23. //When the error occurs,the call stack is like below
  24. //#0  0x00ca3c8a in QListData::isEmpty (this=0x80) at ../../include/QtCore/../../src/corelib/tools/qlist.h:95
  25. //#1  0x00c91b91 in QList<QBoxLayoutItem*>::isEmpty (this=0x80) at ../../include/QtCore/../../src/corelib/tools/qlist.h:139
  26. //#2  0x00b76313 in QBoxLayoutPrivate::deleteAll (this=0x0) at kernel\qboxlayout.cpp:137
  27. //#3  0x004fd8b6 in ~QBoxLayout (this=0x22fe3c, __in_chrg=<value optimized out>) at kernel\qboxlayout.cpp:629
  28. //#4  0x005001de in ~QVBoxLayout (this=0x22fe3c, __in_chrg=<value optimized out>) at kernel\qboxlayout.cpp:1518
  29. //#5  0x004014bd in qMain (argv=1, args=0x92f3698) at ..\Hello_Notepad\main.cpp:19
  30. //#6  0x00401c32 in WinMain@16 (instance=0x400000, prevInstance=0x0, cmdShow=10) at qtmain_win.cpp:131
  31. //#7  0x00401958 in main ()

I am working on windows 7 ultimate,Qt 4.7. I don’t know what’s the difference between the two ways. I think they have the same life time here. And it’s just a example from the Qt doc(http://doc.qt.nokia.com/4.7/gettingstartedqt.html [doc.qt.nokia.com]). Please help me.

19 replies

January 4, 2011

fcrochik fcrochik
Lab Rat
517 posts

I don’t think the issue is with how you instantiate the QWidget. The way Qt works when one object is deleted all its children get deleted. The difference here is just when the QWidget will get deleted – when you use the “new” the object will only get deleted when the application exits and the OS reclaims the memory.

My guess it that you will get the same error using the pointer if you add after line 20 a

  1. delete window;

Most likely the issue is with Qt trying to delete the “textedit” or “layout” objects when the QWidget gets deleted.

Please note that is not good practice to leave for the OS to reclaim memory even if it seems to work.

The following code should work:

  1.     QApplication app(argv, args);
  2.     QTextEdit *textEdit = new QTextEdit();
  3.     QVBoxLayout *layout = new QVBoxLayout();
  4.     layout->addWidget(textEdit);
  5.  
  6.     QWidget window;
  7.     window->setLayout(layout);
  8.     window->show();
  9.  
  10.     return app.exec();

replacing with (starting on line 6):

  1. QWidget *window=new QWidget;
  2. window->setLayout(layout);
  3. window->show();
  4.  
  5.     int ret = app.exec();
  6.     delete window;
  7.     return ret;

should also work.

 Signature 

Certified Specialist & Qt Ambassador Maemo, Meego, Symbian, Playbook, RaspberryPi, Desktop… Qt everywhere!

January 4, 2011

jandin jandin
Lab Rat
3 posts

I think you are right fcrochik ,and I still have a question about your answer that’s why just

  1.     delete window;

but not

  1.     delete textEdit;
  2.     delete layout;
  3.     delete window;

January 4, 2011

fcrochik fcrochik
Lab Rat
517 posts

Like I said Qt will re-parent layout and textedit on setLayout and addWidget. When you delete window they will be deleted automatically.

 Signature 

Certified Specialist & Qt Ambassador Maemo, Meego, Symbian, Playbook, RaspberryPi, Desktop… Qt everywhere!

January 4, 2011

fcrochik fcrochik
Lab Rat
517 posts

This is a paragraph from the “C++ GUI Programming with Qt 4 – 1st edition by Jasmin Blanchette and Mark Summerfield (page 28):

Qt’s parent–child mechanism is implemented in QObject. When we create an object (a widget, validator, or any other kind) with a parent, the parent adds the object to the list of its children. When the parent is deleted, it walks through its list of children and deletes each child. The children themselves then delete all of their children, and so on recursively until none remain.

This is a very good book and the first edition is available as a pdf for free. Look into the “Qt books” wiki.

 Signature 

Certified Specialist & Qt Ambassador Maemo, Meego, Symbian, Playbook, RaspberryPi, Desktop… Qt everywhere!

January 4, 2011

jandin jandin
Lab Rat
3 posts

Thanks for your response. If I just follow the Qt doc “Getting Started Programming with Qt”,I think I would get mad. :-)

January 4, 2011

fcrochik fcrochik
Lab Rat
517 posts
jandin wrote:
Thanks for your response. If I just follow the Qt doc “Getting Started Programming with Qt”,I think I would get mad. :-)

Have a look at the book I mentioned before. I usually can’t stand programing books but I found this one very well written and easy to follow. Too bad I didn’t know about it when I started with Qt :(

 Signature 

Certified Specialist & Qt Ambassador Maemo, Meego, Symbian, Playbook, RaspberryPi, Desktop… Qt everywhere!

January 4, 2011

peppe peppe
Ant Farmer
1029 posts

jandin wrote:
  1. #include <QtGui>
  2. #include "mainwindow.h"
  3.  
  4. int main(int argv, char **args)
  5. {
  6.     QApplication app(argv, args);
  7.     QTextEdit textEdit;
  8.     QVBoxLayout layout;
  9.     layout.addWidget(&textEdit);
  10.  
  11. //    1.If I use the object,I will get an error whe I quit the application.
  12. //    Debug it,I get a signal SIGSEGV which means Segmentation fault
  13.     QWidget window;
  14.     window.setLayout(&layout);
  15.     window.show();
  16. //     2.But if I use the poniter ,it is ok.
  17. //     QWidget *window=new QWidget;
  18. //     window->setLayout(&layout);
  19. //     window->show();
  20.     return app.exec();
  21. }
  22. </blockquote>
  23.  
  24. You really need to learn C++ and figure out why the two ways of doing things are different.
  25.  
  26. First of all, as people already said, you're implicitly using QObject parent/children mechanism, which means that destroying an object will automatically destroy all of its children.
  27.  
  28. Second, what's going on here is mandated by the C++ standard: automatic object destruction happens in the reverse order than automatic object construction, that is, the last object created is the one that is destroyed first.
  29.  
  30. What's the last object that was built? The "QWidget window". And its dtor wipes out (with _operator delete_) all its children, namely the layout and the textedit, which were allocated on the stack. Uh oh... operator delete on an object on the stack. That's *WRONG!*
  31.  
  32. What happens then? The dtors of the layout and of the textedit objects are run (*WRONG!* and *WRONG!* again, or, *WRONG²!*). Well, it's too late. Your program's memory layout is already FUBAR, and you've probably already got a weird crash by now.
  33.  
  34. If you use the @QWidget *window = new QWidget
approach instead your application will leak memory (WRONG!) and tools like valgrind will complain and report: you never free the memory allocated there.

Of course, adding a

  1. delete window
(GOOD!) line after app.exec() will crash your application for the same reason stated above (WRONG!).

So, what you can do about that? Either

  • allocate everything on the heap with operator new, then delete ONLY the widget with operator delete;
  • allocate everything on the stack, but ensure that automatic object deletion doesn’t interfere with QObject parent/children management, f.i.
    1. w.setLayout(&l);
    2. l.addWidget(&te);
    3. w.show();

    will do the right thing (but think about why it will).

 Signature 

Software Engineer
KDAB (UK) Ltd., a KDAB Group company

January 4, 2011

jandin jandin
Lab Rat
3 posts

peppe wrote:

jandin wrote:
  1. #include <QtGui>
  2. #include "mainwindow.h"
  3.  
  4. int main(int argv, char **args)
  5. {
  6.     QApplication app(argv, args);
  7.     QTextEdit textEdit;
  8.     QVBoxLayout layout;
  9.     layout.addWidget(&textEdit);
  10.  
  11. //    1.If I use the object,I will get an error whe I quit the application.
  12. //    Debug it,I get a signal SIGSEGV which means Segmentation fault
  13.     QWidget window;
  14.     window.setLayout(&layout);
  15.     window.show();
  16. //     2.But if I use the poniter ,it is ok.
  17. //     QWidget *window=new QWidget;
  18. //     window->setLayout(&layout);
  19. //     window->show();
  20.     return app.exec();
  21. }
  22. </blockquote>
  23.  
  24. You really need to learn C++ and figure out why the two ways of doing things are different.
  25.  
  26. First of all, as people already said, you're implicitly using QObject parent/children mechanism, which means that destroying an object will automatically destroy all of its children.
  27.  
  28. Second, what's going on here is mandated by the C++ standard: automatic object destruction happens in the reverse order than automatic object construction, that is, the last object created is the one that is destroyed first.
  29.  
  30. What's the last object that was built? The "QWidget window". And its dtor wipes out (with _operator delete_) all its children, namely the layout and the textedit, which were allocated on the stack. Uh oh... operator delete on an object on the stack. That's *WRONG!*
  31.  
  32. What happens then? The dtors of the layout and of the textedit objects are run (*WRONG!* and *WRONG!* again, or, *WRONG²!*). Well, it's too late. Your program's memory layout is already FUBAR, and you've probably already got a weird crash by now.
  33.  
  34. If you use the @QWidget *window = new QWidget
approach instead your application will leak memory (WRONG!) and tools like valgrind will complain and report: you never free the memory allocated there.

Of course, adding a

  1. delete window
(GOOD!) line after app.exec() will crash your application for the same reason stated above (WRONG!).

So, what you can do about that? Either

  • allocate everything on the heap with operator new, then delete ONLY the widget with operator delete;
  • allocate everything on the stack, but ensure that automatic object deletion doesn’t interfere with QObject parent/children management, f.i.
    1. w.setLayout(&l);
    2. l.addWidget(&te);
    3. w.show();

    will do the right thing (but think about why it will).

thanks peppe,I can understand it totally now.

  1. allocate everything on the heap with operator new, then delete ONLY the widget with operator delete;
  2. allocate everything on the stack, but ensure that automatic object deletion doesn’t interfere with QObject parent/children management

So the example in the Getting Started Programming with Qt [doc.qt.nokia.com] is wrong. It should be corrected.

January 4, 2011

Gerolf Gerolf
Robot Herder
3287 posts

Hi,

it goes a but farer. You should give the textedit a parent, as the text edit is not automatically reparented. So it should look like this:

  1.     QApplication app(argv, args);
  2.  
  3.     QWidget window;
  4.     QVBoxLayout *layout = new QVBoxLayout();
  5.     window.setLayout(layout);
  6.     QTextEdit *textEdit = new QTextEdit(&window);
  7.     layout->addWidget(textEdit);
  8.  
  9.     window.show();
  10.  
  11.     return app.exec();

The top level widget can be created on the stack, so it is then deleted automatically, or you can create it on the heap and use a smart pointer (scoped ptr) to automatically delete it. But child widgets MUST be created on the heap.

 Signature 

Nokia Certified Qt Specialist.
Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

January 4, 2011

Volker Volker
Ant Farmer
5428 posts
Gerolf wrote:
it goes a but farer. You should give the textedit a parent, as the text edit is not automatically reparented.

It actually is reparented. That’s why the sample program of the getting started guide crashes.

January 4, 2011

Volker Volker
Ant Farmer
5428 posts
jandin wrote:
Thanks for your response. If I just follow the Qt doc “Getting Started Programming with Qt”,I think I would get mad. :-)

Unfortunately the sample code in the Getting Started Guide is wrong and causes the application to crash. See the thread Getting started example is buggy [developer.qt.nokia.com], it has a working version of the sample.

January 4, 2011

peppe peppe
Ant Farmer
1029 posts

Gerolf wrote:
Hi,

it goes a but farer. You should give the textedit a parent, as the text edit is not automatically reparented. So it should look like this:

Actually not; putting it into the layout will automatically reparent it.

 Signature 

Software Engineer
KDAB (UK) Ltd., a KDAB Group company

January 4, 2011

peppe peppe
Ant Farmer
1029 posts

And here we go with another “the thread has changed while posting” … :-)

 Signature 

Software Engineer
KDAB (UK) Ltd., a KDAB Group company

January 4, 2011

Gerolf Gerolf
Robot Herder
3287 posts
Volker wrote:
Gerolf wrote:
it goes a but farer. You should give the textedit a parent, as the text edit is not automatically reparented.

It actually is reparented. That’s why the sample program of the getting started guide crashes.

But it’s only reparented, if the layout already is set to a widget, so creating the layout, adding widgets and the setting the layout to it’s parent does not work.

 Signature 

Nokia Certified Qt Specialist.
Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

January 4, 2011

peppe peppe
Ant Farmer
1029 posts
Gerolf wrote:
But it’s only reparented, if the layout already is set to a widget, so creating the layout, adding widgets and the setting the layout to it’s parent does not work.

Yes it does. And does the right thing.

  1. #include <QtGui>
  2.  
  3. int main(int argc, char **argv)
  4. {
  5.     QApplication app(argc, argv);
  6.     QHBoxLayout *layout = new QHBoxLayout;
  7.     layout->addWidget(new QTextEdit);
  8.     QWidget w;
  9.     w.setLayout(layout);
  10.     w.show();
  11.     return app.exec();
  12. }

 Signature 

Software Engineer
KDAB (UK) Ltd., a KDAB Group company

Page  
1

  ‹‹ [ANSWERED] Operator Overloading with Pointers      [ANSWERED] Include Files ››

You must log in to post a reply. Not a member yet? Register here!