My pet project has come to the point where I should start tracking pointer lifetime, and I'm trying to develop some system for it. Sadly, the popular advice to use smart pointers everywhere does not apply since Qt API itself uses naked pointers on every occasion. So, what I came up with is this:
For everything owned by Qt,
use pointers naked locally;
pass them between functions naked too;
store them as a subclassed QPointer that makes isNull() check before conversion to naked.
For everything cleanly owned by me, use smart pointers as advised. I'm going to go with the std:: versions here.
The case that bothers me. For objects that switch ownership (like widgets added/removed from a layout)
use, store, pass pointers naked;
delete them manually when appropriate.
Suggestion, comments, advice? I don't like this scheme much myself.
First, hold things by value where you can. View each use of new, make_unique and make_shared with suspicion - you must justify each dynamic object creation. If a sub-object has the same lifetime as the parent, holding by value is a no-brainer. For example:
class MyWidget : public QWidget {
Q_OBJECT
QGridLayout m_topLayout{this};
QLabel m_sign{"Hello World"};
public:
MyWidget(QWidget * parent = nullptr) : QWidget{parent} {
m_topLayout.addWidget(&m_sign, 0, 0);
}
};
You're passing pointers around, but object ownership is clear and there's no change of ownership. Just because a QObject has a parent doesn't mean that the parent "owns" it. If the child is destructed before the parent, the ownership ceases. By using C++ semantics - namely the well-defined order of member construction and destruction - you have full control over child lifetimes and no QObject parent gets to interfere.
If you have non-movable objects that have one owner, use std::unique_ptr and move it around. That's the way to pass dynamically created QObjects around your own code. You can remove them from the pointer at the point where you make their ownership managed by a QObject parent, if there is such.
If you have objects with shared ownership, where their life should end as soon as possible (vs. when the application terminates, or some long-lived object gets destroyed), use std::shared_ptr. Ensure that the pointer outlives the users. For example:
class MyData : public QAbstractItemModel { /* ... */ };
class UserWindow : public QWidget {
Q_OBJECT
std::shared_ptr<MyData> m_data; // guaranteed to outlive the view
QTreeView m_view;
public:
void setData(std::shared_ptr<MyData> && data) {
m_data = std::move(data);
m_view.setModel(m_data.data());
}
};
This example is perhaps contrived, since in Qt most users of objects watch the object's destroyed() signal and react to the objects destruction. But this makes sense if e.g. m_view was a third-party C API object handle that had no way of tracking the data object's lifetime.
If the object's ownership is shared across threads, then the use of std::shared_ptr is essential: the destroyed() signal is only usable within a single thread. By the time you get informed about object deletion in another thread, it's too late: the object has been already destroyed.
Thirdly, when you return instances of dynamically created objects from factory methods, you should return them by a naked pointer: it's clear that a factory creates an object for someone else to manage. If you need exception safety, you can return a std::unique_ptr instead.
For starter, in Rome, be Roman.
QT was developed in the very early 90's and it was a great success at a time.
unfortunately, QT didn't really adopted new features as the time went by so the API itself has very old C++ style to it (and may I say, a Java style to it?)
you can't force QT to suddenly be C++14 because it's not. use the popular-QT conventions when it comes to QT. use raw pointer if that was the platform design goal. use value types when you can't.
But I don't think you make QT work that much with C++14. stick the QT idioms as they given by the platform.
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.
When calling C++ from QML, a QObject can be returned to qml by pointer. Before returning, I can call
QObject* qobj = m_sharedPtr.data(); // Pointer to member shared-ptr-managed object.
QQmlEngine::setObjectOwnership(qobj, QQmlEngine::CppOwnership);
return qobj;
but given that QML is garbage-collected, how can this work safely? My mental model is that QML will get the pointer and hold onto it, wrapped in some QML pointer wrapper and that pointer wrapper will eventually be GC'd. But then there's no limit to how long after the setObjectOwnership call that QML could access *qobj. (E.g., perhaps the next QML->C++ call after this one causes m_sharedPtr to go out of scope.) Does that mean QQmlEngine::CppOwnership is only safe to use when the object's lifetime is essentially infinite (e.g., a singleton)? I don't see any alternative, but haven't found any mention of this issue in any documentation.
If m_sharedPtr refers to data created in C++, qobj will have CppOwnership anyways, and you should handle it like any other C++ smart pointer (i.e. let it live as long as you actually need it).
If it was created in QML, it will have JavaScriptOwnership by default. If you then transfer ownership to C++, and it gets destroyed, it's not accessible in QML anymore.
If it is important that qobj is accessible in QML for an uncertain time, but still C++-managed, you could retreat to using raw pointers and handle the destruction yourself (e.g. by connecting to the aboutToClose() signal of a QML window).
I am pretty new to Qt and C++ (been working on C# and Java all my life) and I have been reading almost everywhere that I shouldn't use raw pointers anymore (beside the ones in constructors and destructors, following RAII principle).
I am okay with it but there is a problem that I cannot easily resolve without pointers.
I'll try to explain my problem.
I am creating a QList of a custom class created by me (MyClass) that will act as a model for my application:
QList<MyClass> modelList;
This QList is updated (items added, removed or updated) by a worker thread on the basis of the information arriving from the network.
So far so good.
Now I have another thread (GUI one) that has a QList of drawable items (MyDrawableItem). Each of these items has a member that must point to one of the items in the first QList (modelList), like this:
QList<MyDrawableItem> listToDraw;
where:
class MyDrawableItem
{
private:
MyObject *pointedObject;
//List of many other members related to drawing
}
because everytime a timer in the GUI thread expires I have to update the drawing related members on the basis of the pointed object. Must note that it is safe to keep a pointer to members of QList as stated in the documentation:
Note: Iterators into a QLinkedList and references into heap-allocating
QLists remain valid as long as the referenced items remain in the
container. This is not true for iterators and references into a
QVector and non-heap-allocating QLists.
Internally, QList is represented as an array of T if sizeof(T) <=
sizeof(void*) and T has been declared to be either a Q_MOVABLE_TYPE or
a Q_PRIMITIVE_TYPE using Q_DECLARE_TYPEINFO. Otherwise, QList is
represented as an array of T* and the items are allocated on the heap.
How could this be feasible without using pointers? Or even better what should be the best way to do this kind of work?
I found three possible solutions:
Instead of keeping pointedObject as member of MyDrawableItem, keep the index of the pointed object in the modelList. Then on the update go look inside the QList. But what if the item in the list is removed? I could signal it but if the update happens before the slot is called?
Don't keep anything at all as a member and connect two signals to MyDrawableItem. One signal is updateDrawing(const MyObject&) that updates the drawing-related members and another signal is removeDrawing() that simply deletes the object. This way I don't have to worry about the syncronization between the threads because the MyDrawableItem object won't ever look at the content of the QList. In this case I could be updating the item very often with lots of signals while I only want to update the GUI once in a while (timer of 500 ms).
Simply use pointers.
Evolve and use QSharedPointers but I have never used those and I don't know if that is the best option.
I think that neither of these solutions is the perfect one so I am here asking for your help.
How do the standard views in Qt (tableview, listview, ecc.) deal with this problem?
How should I deal with it?
Please help me, I am thinking about this from yesterday and I don't want to make a mess.
Thanks a lot!
An addition to #Benjamin T's answer:
If you do decide to go for option 4 and use QSharedPointer (or the std variant), you can actually control ownership somewhat using "weak pointers". Weak pointers store a reference to the object, but do not own it. Once the last "strong pointer" gets destroyed, all the weak pointers drop the reference and reset themselves to nullptr.
For your concrete example, you could use a QList<QSharedPointer<MyClass>> for the model and use QWeakPointer<MyClass> in the drawable classes. Before drawing you would create a local QSharedPointer<MyClass> in the drawing function and check if it is valid.
I would still recommend you to use 2/3, as recommended by Benjamin. Just a small addition.
It is the current trend among the C++ community, especially if you look at all the CppCon conferences to discourage the use of raw pointers.
This trend is not without sold basis, as the use of std::shared_ptr and std::unique_ptr as well as std::make_unique and std::make_shared can help a lot memory management and prevent some pitfalls (like having an exception thrown during a call to a constructor).
However, there is nothing absolute in this "do not use raw pointers" trend and raw pointers can still be used and smart pointers do not solve all memory management problems.
Concerning the case of Qt, if you are dealing with QObject derived class and you properly parent your objects you are kind of safe as you have an owning hierarchy and parents QObjects will destroy their children. This is very important if you are also using QThread as QObject instances are associated with a QThread and all instances in a QObject hierachy are associated with the same thread.
Regarding your solutions:
Bad idea, you need to sync your list and the indexes all the time.
It could be an idea, but it changes the architecture of your software. Does MyObject really needs to know about MyObject ? If the answer is 'no', signal/slots seems a better solution. It might indeed require some work to solve your refresh rate issue, but this is off-topic.
It might look like a good idea, especially if your objects are inheriting QObject. Also you may want to use QVector<T *> and std::vector<T *> and let the QObject hierarchy deals with life span of your objects. You can listen to the destroyed() signal to know when the object are destroyed, or use QPointer. However, it does not solve the thread safeness on your consumer side, as the object might be deleted at any point in time from another thread.
If you cannot do 2, this is the option to go for. You just have to take care to not have cyclic dependencies or you will leak memory. However, this might be a bad idea if you want that when you delete an object in your list then it gets removed from your GUI object. If you simply keep a shared pointer, you will never know that it was removed from the list. As stated by #Felix, you can store weak pointers and convert them to shared pointers only when needed, but if you have consumers in multiple threads, then you may never delete the object. Also you have to make MyObject thread-safe as you are mutating it states from one thread and reading it from another thread. Using option 4 does change the owning model of your software: in the current state the QList owns the instances, with option 4 the ownership is shared with anyone getting a shared pointer.
My personal choice would be to replace the QList with a QVector of pointers.
If your objects inherit from QObject, then I would parent all the objects in the QVector to the object that owns the QList/QVector. This is to ensure proper parenting and thread association.
Then I would try option 2, and only if option 2 fails go for option 4.
Here is an exemple:
class MyClass : public QObject
{
Q_OBJECT
public:
explicit MyClass(QObject *parent = nullptr);
signals:
void stateChanged(int state);
};
class Owner : public QObject
{
Q_OBJECT
public:
explicit Owner(QObject *parent = nullptr);
void addObject(MyClass *obj) {
obj->setParent(this);
m_objects.append(obj);
}
void removeObject() {
delete m_objects.takeFirst();
}
private:
QVector<MyClass *> m_objects;
};
class Consumer : public QObject
{
Q_OBJECT
public:
explicit Consumer(QObject *parent = nullptr);
public slots:
void onStateChanged(int state) {
m_cachedState = state;
}
private:
int m_cachedState = 0;
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QThread thread;
thread.start();
Owner owner;
Consumer consumer;
consumer.moveToThread(&thread);
MyClass *object = new MyClass();
owner.addObject(object);
QObject::connect(object, &MyClass::stateChanged, &consumer, &Consumer::onStateChanged);
return app.exec();
}
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
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.