Sorry for the dumb question, but I'm working with Qt and C++ for the first time, and working through the tutorial and some samples.
One thing that was mentioned was that Qt stuff doesn't need to be explicitly deleted. So, main question, does this also apply to collections of Qt stuff? Like say I want a dynamic number of MyWidgets, so I keep a vector or whatever of them. Are they still taken care of for me?
As a side question, what is going on to make it so I don't have to worry about destructors?
The Qt memory management model is based upon a parent-child relationship. Qt classes take an optional parent as a parameter of their constructor. The new instance registers with this parent such that it is deleted when the parent is deleted. If you are using a Qt collection (e.g. QList), I believe you can set the list as the parent of its entries. If you're using an std::vector or other collection type, you will not get "automatic" memory management.
The Qt model makes a lot of sense in a UI hierarchy where it matches one-to-one with the UI hierarchy. In other cases, it doesn't always map as cleanly and you need to evaluate whether using the Qt system makes sense for the particular situation. The normal C++ tools still work: you can use std::tr1::shared_ptr or any of the other smart pointer classes to help you manage object lifetime. Qt also includes QPointer, a guarded pointer, and the QSharedPointer/QWeakPointer pair that implement a reference-couting smart pointer and weak-reference pair.
Qt has an interesting object model for sure. When I first started it made me uneasy that there were so many new Foo calls and no deletes.
http://qt.nokia.com/doc/4.6/object.html Is a good place to start reading up on the object model.
Things of interest:
QObject subclasses have their assignment and copy-ctor methods disabled. The chain of object child-parents is maintained internally by QObject.
Generally when instantiating a QObject subclass (if you don't plan on managing its pointer yourself) you will provide another QObject pointer as the parent. This 'parent' then takes over the management of the child you just made. You can call setParent() on a QObject to change who "owns" it. There are very few methods in Qt that will change the parent of an object, and they all explicitly state that they do in the docs.
So to answer your specific question: it depends on how you made all of your MyWidget instances.
If you made each one with a parent, then no you don't have to delete them. The parent will delete them when it gets deleted.
If you're keeping a QList<MyWidget*> collection of them, and you didn't give them a parent, then you should delete them yourself.
Related
I have gone back to Qt/C++ programming recently after coding a lot with plain C++.
When browsing StackOverflow, I often catch up on posts like "Why use pointers?" where in most cases the gist of the answers is "if you can avoid it, don't use them".
When coding in C++, I now mostly try using stack variables which are passed by (const) reference or, if necessary, std::shared_ptr resp. std::unique_ptr where needed.
Getting back to Qt, I found all those "principles" to be completely ignored apparently.
I know that Qt uses its own memory management to take care of raw pointers, but here's my question:
Why don't they at least use shared_ptr or unique_ptr, particularly since they even have an own implementation QSharedPointer?
Qt since versions 4.x was designed around imitating Java's framework ideology in C++ environment, using C++98 means. Instead of RAII approach of interaction it establishes "owner" - "slave" relation, in framework's term that's "parent" and "child". More of, Qt uses concept of PIMLP -private implementation. QObjects you operate with aren't real representation of what is happening, they are interfaces to completely hidden inner implementation.
By design, you have to create a QObject-derived object of child element and pass ownership to the owning object . E.g. where a window is an owner, a Button inside window will be the "slave" object. When owner is deleted, all objects that were slaved to it will be deleted too. All QObjects are thread-aware, but QWidgets can work only in main thread. This creates a non-owning pointer:
QWidget *myWidget = new QWidget(mainWindow);
mainWindow will be owning QWidget instance in this case. But this one is owning?
QWidget *myWidget = new QWidget;
It isn't. It's still owned by QApplication.
QObjectDerivedClass *myWidget = new QObjectDerivedClass;
It's an owning pointer, but this object was registered to exist in our framework. Even more, any instance can be found if it was assigned a name, storing QObjects to reach them is just an caching optimization.
All QObjects and QWidgets are registered globally and are iterable. With destruction of QApplicationCore instance all QWidgets of top level will be freed. There is undocumented exception out of that rule at least in Qt 4.x versions that QDesktopWidget objects are ignored even if they are top-level widgets. So, if a QMainWindow was forced to appear on certain screen by becoming its child, it wouldn't be destroyed.
Now comes into play signal-slot connections. In GUI certain handlers begin their work as soon as parent-child connection is established, but you can add new handlers. if a child object is deleted between beginning and end of message pump created by QEventLoop, your program may encounter an UB. To avoid it, you have to call deleteLater() which marks object for deletion at designed moment. Processing signals between threads is done separately. Practically, the main event loop is the only part of GUI that is synced with other threads.
With such complex structure and already existing requirement of working in one thread, imposed by some of supported embedded platforms, need to use smart pointers within GUi framework was negligible compared to possible impact on performance.
Before C++11 Qt had QPointer (and still got it), which is aware if QObject still exists or not using mechanics similar to owner-child interaction.
This design predates C++11 and QSharedPointer appeared only after that to fill a niche requested by users to maintain user-defined data model. It doesn't support some features, e..g you can't have an atomic version of it like ISO version does, it's only partially atomic until very last releases of 5.x. QAtomicPointer isn't either QPointer or QSharedPointer, it acts like a std::atomic<QObject*>. QSharedPointer though allows use of custom non-standalone deleter, including a call of deleteLater():
QSharedPointer<MyDataQObject> objPtr { new MyDataQObject, &QObject::deleteLater };
Assuming that MyDataQObject is derived from QObject, objPtr will call method deleteLater() in context of managed object instead of using delete on managed pointer when destroyed or reset.
I have a class called Widget. This class is abstract and has virtual methods. To avoid object slicing all Widgets are stored as references or pointers. I have several classes with constructors that store internally the widget given to them; thus the Widget stored must have been initialized outside the constructor and cannot be destroyed before the object is, therefore usually the Widget is allocated via dynamic memory. My question is regarding how to handle this dynamic memory; I have compiled a list of options (feel free to suggest others.) Which is the most idiomatic?
1. Smart pointers. Smart pointers seem like the right choice, but since I'm using C++98 I have to write my own. I also think that writing smart_pointer<Widget> all the time is a little ugly.
2. Copy Widgets when stored. Another course of action is to store a copy of the passed-in Widget instead of the original. This might cause object-slicing, but I'm not sure. Also, users might want to write classes themselves that store passed-in Widgets, and I wouldn't want to make it too complicated.
3. Let the user handle everything. I could perhaps make the user make sure that the Widget is deleted on time. This seems to be what Qt does (?). However, this again complicates things for the user.
I personally like this approach (it is not always applicable, but I used it successfully multiple times):
class WidgetOwner
{
vector<Widget*> m_data;
public:
RegisterWidget(Widget *p) { m_data.push_back(p); }
~WidgetOwner() { for (auto &p : m_data) delete p; }
};
This simple class just stores pointers. This class can store any derivatives of Widget provided that Widget has virtual destructor. For a polymorphic class this should not be a problem.
Note that once Widget is registered, it cannot be destroyed unless everything is destroyed.
The advantage of this approach is that you can pass around pointers freely. They all will be valid until the storage will be destroyed. This is sort of hand made pool.
Which is the most idiomatic?
The most idiomatic would certainly be what next versions of c++ decided to be "the way to go", and that would be smart pointers (You can find/use an implementation on boost for example, also other ones on the internet might be simpler for inspiration).
You can also decide that since you are using c++98 (that's a huge factor to take into consideration), you take what's idiomatic for that context, and since that was pretty much no man's land, the answer is most likely whatever home made design is the most appealing to you.
I think smart pointer is best choice. And if you feel template is ugly, try the typedef
My goal is this:
QWidget *p = new QSpinBox(0); // This can be any type of QWidget.
QWidget* Get()
{
/*
Here using p, I need to return a NEW object of QSpinBox or whatever
the qwidget assigned to p. I can't return p because it will be deleted
after this method, so the next time p would be empty.
*/
}
It's used for the QStyledItemDelegates::createEditor() method. The widget returned from get will be deleted when the delegate editing is done.
All QObjects are not copyable by definition. See its header file.
Same applies to QSpinBox.
Reason is simple cloning of signal slots memory management could lead to unpredictable results, so it was disabled by design.
The copy of a pointer to an object doesn't copy the object in any way. In Qt the copy of QObject derived classes is indeed disabled, but you can copy pointers to the object around as much as you want, or until you run out of memory...
Due to the design of Qt QObject derived classes have unique identities. This means they must not be copied, at least in the rational sense of the term. You could however write your own "clone function" that creates a new instance with unique identity and applies all of the properties of the object p points to to the new instance. E.g. you can fake it to a certain amount but don't expect to get a copy functionally identical to the original. If you want to get a fully functionally identical clone, you will have to implement your own signal and slot mechanism instead of using the one provided by Qt.
You CAN indeed return p - but it will point to nothing if you call delete on it. Keep in mind returning p will simply copy the pointer, it has nothing to do with the actual object pointed to. p is just a number.
Edit:
At a deeper look at the "reflection facilities" provided by Qt, it looks like you could get signals and slots to clone, but it is not pretty - you have to query every QMetaMethod of the QMetaObject associated with the particular instance to find the signals, but then you hit a brick wall - you will have to resort to using private APIs (a big no-no in 99.9999% of the cases) in order to query for the signal receivers in order to connect the new copy to them as well. Definitely not something that was intended to be done. In short, you need to rethink your strategy at getting the problem solved.
Overall, as I mentioned in the comments, your problem seems to be bad design, and even though it is technically possible to make the bad design work, you'd be much better if you simply improve your design and avoid arduous if not even masochistic endeavors.
s is a pointer, which can be copied and modified at will; modifications to the copy will never affect the original. If what you meant was in fact the object which s referred to, then it's sufficient to provide it with a copy constructor and a copy assignment operator; depending on the content of the class, the compiler may have generated these for you.
Depending on the content, it's also possible that the compiler generated versions don't do what you need.
Given the name of the class, I suspect that it is part of Qt. In that case, check the documentation. It may support cloning, in which case, what you probably want is a clone.
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 ?
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 :).
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.
The problem you're seeing is that you're not thinking about what is happening. The QPushButton instances in the class are created and owned by the class. When the class is deleted, it will call the destructor on the QPushButtons.
Qt provides useful parenting of objects and deleting a parent will handle deletion of all its child objects.
So, in the case of your example, you have two things that are going to call the destructor on the QPushButtons: 1) The deletion of the class object for ThumbnailDialog and 2) The deletion of the buttonlayout, which will try to delete its children and will fail, as the object is on the stack.
What you can do, if you really want, is ensure that the QPushButton items are removed from the button layout, in the destructor of ThumbnailDialog by calling removeWidget() on the button layout.
However, this is messy. Dynamic allocation is a much better method, as it allocates objects on the heap and not the stack.
Also note, with Qt's parenting, it means that you can create a lot of widgets without needing to keep track of them. For example, you can do this: -
ThumbnailDialog::ThumbnailDialog(QWidget* parent):
QDialog(parent)
{
//...
m_buttonsLayout.addWidget(new QPushButton("Confirm"));
m_buttonsLayout.addWidget(new QPushButton("Cancel"));
//...
setLayout(&m_dialogLayout);
}
In this case, the push buttons don't even need to be defined in the header and you can be assured that they'll be deleted along with their parent.
No, not really. I'm afraid. Qt relies on this stuff.
If you have read the other answers and you still want to use static allocation, you can release the ownership that was taken when doing addWidget():
//...
m_buttonsLayout.addWidget(&m_confirm);
m_buttonsLayout.addWidget(&m_cancel);
// release the ownership by setting no parent
m_confirm.setParent(0);
m_cancel.setParent(0);
//...
My coding practice using Qt can best be described as follows:
If the Widget is going to be actively used (e.g. A QLineEdit which provides text), I declare it in the header file and then initialise it in MainWindow.cpp.
e.g. TextEditor.h:
class TextEditor
{
//other code
private:
QLineEdit edtFind;
};
2.. If a widget is not going to be used (e.g. QLabel, QWidget), or it's part of a signal slot system (e.g. QPushButton), I declare and inialise it inside constructor using new.
-e.g.
TextEditor::TextEditor()
{
//other code
QWidget* searchPanel = new QWidget();
edtFind = new QLineEdit("Enter Search Term");
QPushButton* findButton = new QPushButton("Find");
connect(findButton,SIGNAL(pressed()),this,SLOT(find()));
ui->statusbar->addPermanentWidget(searchPanel);
}
My question is, am I using an efficient approach in point 2? Would it be better to not allocate memory from the heap?
Thanks.
Your approach is not efficient. You should use heap allocated objects when you actually need them:
objects that have a longer lifetime
using a forward declaration in order to avoid including a header file
holding a reference to an object created elsewhere
Your approach is more complicated without any visible benefit. Heap is known to be slow, and allocating a large number of small objects is known to fragment it (this might not make a difference in your app but it's still a bad practice).
While good advise for C++ in general, answer 1 is actually wrong for a big part in Qt: QObject (and with it all widgets, since QWidget derives from QObject). Rule there is to always allocate QObjects on the heap if they have a parent, because QObject features a parent-based garbage collection (when the topmost QObject-parent gets deleted, it will ask all its children to delete themselves recursively). The application may try to delete an object on the stack, which leads to a crash.
Note that some operations in Qt implicitly add or change the parent of a QObject as a side-effect (reparenting), such as adding a widget to a layout. However, this is usually documented in the API documentation. Since reparenting is very common with QWidgets, you should never put them on the stack. Other QObject-derived classes are safer, consult the API documentation in case of doubt.