Unsolved Resource management in Qt
-
meory leak prevention is not the main objective of this system
Up to now, I don't think Qt's parent-child mechanism is completely successful in that objective, because the resources are mainly freed when the project closes. While modern OSes do the same task after closing the program, making Qt's work actually useless in effect.
QPointer also is apparently successful only in preventing dangling pointers and it is different from memory leak.
Have you ever actually used std::unique_ptr?
No, not yet. How about you? ;)
Let me ask you this question,please. How best do you write a parented project like this:
test.h:
#include <QDialog> class QLineEdit; class QSpinBox; class QFormLayout; class Test : public QDialog { Q_OBJECT public: Test(QWidget* parent = nullptr); void do_something_else(); private: QFormLayout* formLayout; QLineEdit* nameLineEdit; QSpinBox* ageSpinBox; };
test.cpp:
Test::Test(QWidget* parent): QDialog(parent) { formLayout = new QFormLayout; nameLineEdit = new QLineEdit; ageSpinBox = new QSpinBox; formLayout->addRow(tr("&Name:"), nameLineEdit); formLayout->addRow(tr("&Age:"), ageSpinBox); setLayout(formLayout); do_something_else(); } void Test::do_something_else() { // Accomplish some other task for several hours }
-
@tomy said in Resource management in Qt:
Up to now, I don't think Qt's parent-child mechanism is completely successful in that objective, because the resources are mainly freed when the project closes.
That's not at all true. The resources are released whenever you release them. It has nothing to do with smart pointers or parent child relation. There's no automatic garbage collection or anything like that. As was said above, you as a designer decide when objects are created and destroyed. If you don't want an object to exist just delete it. Qt doesn't dictate whether you create an object on a stack or a heap. You can delete it whenever you see fit. The parent child relation just lets you conveniently delete the top level object and it will clean all of its children, but you can manually delete them at any point before that if you want.
As to your example - that's just poorly designed code. Nothing to do with Qt. If you want a long lasting task to run and you don't want the dialog to stick around then structure your program like that. Certainly don't run tasks lasting several hours in a blocking call in ui thread. That's just bad.
You can do it like this for example:
class Whatever { TaskSettings get_task_settings() { SomeSettingsDialog dialog; dialog.exec(); return dialog.settings(); } void do_something_else { TaskSettings settings = get_task_settings(); StartTaskInAnotherThread(settings); //and exit immediately } }
Nothing is leaked, no dialog resources are held longer than needed, no smart pointers or otherwise.
-
You radically changed my code and now neither I get any new thing useful from that nor is the ambiguity of that relation more eliminated. I was reading your post of three years ago and was finding it useful.
Just one point is clear to me for this post: smart pointers are created for occasions we "forget" to "delete" a memory block allocated dynamically. If we can write delete whenever needed, so why are modern pointers called "smart"?
auto owner = std::make_unique<QPushButton>();
This since isn't a static member doesn't work either on my Qt Creator!
error: 'auto' not allowed in non-static class member -
@tomy said in Resource management in Qt:
I don't think Qt's parent-child mechanism is completely successful in that objective, because the resources are mainly freed when the project closes. While modern OSes do the same task after closing the program, making Qt's work actually useless in effect.
As stated before - that depends solely on how you build your UI. If you have a GUI app - let's say a web browser - then obviously the UI needs to stay in memory while the application is open. Otherwise users won't see anything... and these resources need to be freed only when the whole application is being closed. There is nothing that smart pointers would change in this scenario.
There are parts of that app, though, that do benefit from more smartness - browser tabs. Each new tab allocates memory, and closing the tab should free that memory. With Qt's approach (parent-child), you don't have any memory leaks here: a tab is created, added to the tree. You can delete it when the tab is closed, but if you forget to do it in code, no memory will leak - Qt will "remember" to free it when application is closed. Using smart pointers here would give you exactly the same result. The programmer still needs to remember to delete/free the memory when necessary for "performance" reasons like that.
Let me ask you this question,please. How best do you write a parented project like this:
What you wrote seems fine. Whether you run some task for several hours or for 1 minute does not matter at all from memory perspective.
-
You can delete it when the tab is closed, but if you forget to do it in code, no memory will leak - Qt will "remember" to free it when application is closed
This is exactly the point I'm referring to. If the user continually opens (creates, dynamically) new tabs during work and closes them forgetting to set "delete" in code, without closing the main window of the browser, Qt releases those tabs' reserved memory beforehand, at the time of closing the app. Right, up to here?
I say it is useless, because most modern OSes do this task exactly when a program closes.
also you say:
Using smart pointers here would give you exactly the same result. The programmer still needs to remember to delete/free the memory when necessary
I disagree with this. Smart pointers have a "delete" in their destructors, so it's guaranteed that when they go out of scope, (just like the new tabs when they are closing), their resources using the destructors of those smart pointers are freed while the app is still running.
With what part of my opinions above do you disagree, please?
-
@tomy said in Resource management in Qt:
Just one point is clear to me for this post: smart pointers are created for occasions we "forget" to "delete" a memory block allocated dynamically. If we can write delete whenever needed, so why are modern pointers called "smart"?
No they are not. They are created for specific circumstances where they're useful. The thing a scoped pointer is useful for is exception-safety. Shared data pointers (Qt) are created for COW (allowing shallow copies) and thus reentrancy. Shared pointers are for when the objects manage their own lifetimes - they're their own owner so to speak. If you don't allow exceptions then stack unwinding a scoped pointer gives you nothing. If your object is not managing its own lifetime then using a shared pointer means you're trying to fit a square peg in a round hole.
This is exactly the point I'm referring to. If the user continually opens (creates, dynamically) new tabs during work and closes them forgetting to set "delete" in code, without closing the main window of the browser, Qt releases those tabs' reserved memory beforehand, at the time of closing the app. Right, up to here?
If they're parented to something, then they're freed when the something is destroyed. It's not Qt's job (nor the OS's for that matter) to clean up your room, you know, is what we're saying. You need to tidy up, that's your responsibility as a programmer. Forgetting to delete what you acquired is a bug in your code, not in the library.
I disagree with this. Smart pointers have a "delete" in their destructors, so it's guaranteed that when they go out of scope, (just like the new tabs when they are closing), their resources using the destructors of those smart pointers are freed while the app is still running.
Same goes for the parent-child relationship. When the parent object goes out of scope (i.e. is deleted) then it's going to free its children, not before that, not at some unknown point in time.
With what part of my opinions above do you disagree, please?
I disagree with two things:
- You're not realizing a smart pointer is not a pointer but an object. The stack frees the object then the object is going to delete the data block.
- This is no different from what the parent does.
-
They are created for specific circumstances where they're useful.
What circumstances, only exceptions?
So you agree that, when each new tab in the browser example is created using a smart pointer, its resource will be freed when it closes, not necessarily at the time the user closes the whole app.
You're not realizing a smart pointer is not a pointer but an object.
I know that. Once again in the above example, when a new tab closes, that "object" goes out of scope handling the destructor of its class to run freeing the newly closed tab's resource.
So if this scenario is done properly with smart pointers, and you say the same goes with the parent-child relationship if they're parented to something, OK. What is that thing, in our example? The main window of the browser?
-
@tomy said in Resource management in Qt:
What circumstances, only exceptions?
Only? That's enough not to leak memory all over the place.
So you agree that, when each new tab in the browser example is created using a smart pointer, its resource will be freed when it closes, not necessarily at the time the user closes the whole app.
No, I don't.
Once again in the above example, when a new tab closes, that "object" goes out of scope handling the destructor of its class to run freeing the newly closed tab's resource.
There's no such example that I could see.
So if this scenario is done properly with smart pointers, and you say the same goes with the parent-child relationship
It does.
if they're parented to something, OK. What is that thing, in our example? The main window of the browser?
Usually (actually almost always) you parent widgets to their visual parent. For a tab that could be a dialog or a main window. For a dialog it can be another dialog or a main window, etc. None of the smart pointers can know if you want to free the object when you close the tab or not, so that's up to you. You can for example want the tab to persist over some time, even if not visible. And I've done this, whenever I have a widget that's heavy to populate for w/e reason. On the other hand when the dialog's deleted its going to free all it's child widgets (provided they're parented), so I really don't see why you'd want to even use a smart pointer in that case. Moreover I'd rather create the widgets on the stack, where applicable, then the language is freeing them for me, no need to call
new
, nordelete
. -
Thank you.
The issue still is not solved for me, but I would rather not continue this thread because it's just this way being stretched out more and more.Probably, in the future, or when studying other resources, I can comprehend the matter.
-
@tomy Just my 2 cts about parent relationship of QtObject. This has nothing to do with smartpointer philosophy, the point is to ensure than every child object will be distroyed when the parent object is distroyed.
So combining smartpointers and parent-child relationship is a very bad idea, because smartpointer are there to clear memory when all copies of the pointer are distroyed... So you will have double memory release ==> crash!
But Qt also includes another type of smartpointer calledQPointer
, which will becomes null when the QObject is deleted, and distroying the the QPointer, will notThe other advantage of parent-child relationship, is that parent and childs always living in the same thread, moving parent object to another will also move all child to the same thread. Moving childs to another thread is not allowed.
There is only 1 rule about parent-child relationship and smartpointer, avoid to combine them.