Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any way to use Qt without using dynamic memory for everything?

So, I think I've searched the web quite thoroughly about this and found nothing really useful (just confusing at most...).

I'd like to know how I can (if possible) use Qt with non-dynamic memory. The problem I face is that for many widgets, I know exactly what I want to use (these sub-widgets, these layouts, in fixed numbers, etc.). Yet, everything in Qt seems to get in the way when you don't use dynamic memory. A simple example is QLayout, which from the Qt documentation is designed to take ownership of anything it is added. So basically, the following code:

//In header
class ThumbnailDialog : public QDialog
{
    Q_OBJECT
public:
    ThumbnailDialog(QWidget* parent = 0);
    ~ThumbnailDialog(void);
private:
    QPushButton m_confirm;
    QPushButton m_cancel;

    QHBoxLayout m_buttonsLayout;
};

//Implementation of ctor
ThumbnailDialog::ThumbnailDialog(QWidget* parent):
    QDialog(parent)
{
     //...
     m_buttonsLayout.addWidget(&m_confirm);
     m_buttonsLayout.addWidget(&m_cancel);
     //...
     setLayout(&m_dialogLayout);
}

...will end up (on MSVC) in a debug assertion fail for _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) because, in the ThumbnailDialog's dtor, the layout tries to delete the buttons... which it obviously shouldn't.

So, am I forced to use dynamic memories everywhere, as this "Qt Expert" advocates (while mentioning "heap", though...) ? This seems wrong as this prevents taking advantage of RAII (if parent-child relation means there'll be a delete, one can't use smart pointers to do that I suppose, then). It also feels terribly wrong to resort to dynamic memory for things known at compile-time... (but I could be wrong, that's just my feeling).

So: is there any way of using Qt without resorting to dynamic memory and news for every single widget/layout ?

like image 258
JBL Avatar asked Dec 13 '13 14:12

JBL


People also ask

What is the difference between heap and stack?

The Heap Space contains all objects are created, but Stack contains any reference to those objects. Objects stored in the Heap can be accessed throughout the application. Primitive local variables are only accessed the Stack Memory blocks that contain their methods.

Does initialization allocate memory?

Allocation is binding a variable to a memory location and initialization is assigning a value to that variable.


2 Answers

I think you are misunderstanding the problem here. You are not double deleting something, you are deleting an object allocated on the stack:

 int foo = 12345;
 int* pFoo = &foo;
 delete pFoo;

This is what happens when you pass a pointer to a stack based object to QHBoxLayout, hence your heap corruption debug assert.

Qt manages QObjects this way because most GUI's have LOTS of widgets, which makes managing GUI object life times easier, it also allows queued deletes across threads etc. Also internally most classes use PIMPL's so you are not avoiding the heap/dynamic allocation even if your code worked.

Having said all this you can get it to work without the heap alloc if you wish, but it is far more effort than its worth. In your example you would have to remove the widgets from the layout in the destructor, but be sure the nullptr check things in case the ctor has thrown, if they're not in the layout when its destructor is hit then it won't be able to delete them.

One more thing to think about.. if Qt was designed to work this way then you could easily end up in the situation where you overflow the stack on some platforms. E.g Qt works on Symbian/S60 which has extremely limited stack, running your code there could easily cause a stackoverflow :).

like image 138
paulm Avatar answered Oct 06 '22 00:10

paulm


Yes, there is. (and in a pretty clean way, I believe)

You just have to be aware about the order of destruction of your QObject hierarchy:

  • As explained in the Qt docs, a lot of objects claim ownership of their children and therefore want to make sure they get cleaned up when they die.
  • QObject’s dtor relieves its parent of that ownership.
  • Destruction of non-static data members happens from bottom to top.

Which means that, in your case, you just have to move the layout to the top:

private:
    QHBoxLayout m_buttonsLayout;

    QPushButton m_confirm;
    QPushButton m_cancel;

All the layout’s children’s dtors unregister themselves from the layout, so when the layout destruction happens there are no registered childs left. Previously the layout’s destruction deleted the children which where not newd in the first place.

This may seem tedious at first sight, but in practice the hierarchy within a custom widget is pretty flat. The order of widgets in one layer of the hierarchy – in this case the QPushButtons – is not important which usually means that you only have to arrange the layouts on top properly.

like image 24
Darklighter Avatar answered Oct 05 '22 23:10

Darklighter