Solved Should every class in Qt derive from QObject?
-
What if I don't need signals and slots in particular class and all I'm interested in is garbage collection? Should I go with non qt class instead and use just
QSharedPointer
or delete? That would eliminate the heavinessQObject
inheritance adds.Let's say I have class that depends on another class for example
Store
andStoreItem
.StoreItem
constructor is defined as follows:StoreItem(Store *store)
it has a member pointer to
Store
so you know to which store it belongs. TheStore
class hasQVector<StoreItem*>
orQVector<QSharedPointer<QStoreItem*>>
inside and functions likeStoreItem *addItem(...)
.Should
StoreItem
be aQObject
class or non qt class?
ShouldStore
be aQObject
class?What are general rules when to inherit
QObject
and when not? -
@enemyofthedawn If I'm not going to use signals/slots in the class then I don't inherit from QObject.
Then if I need something from QObject later I just add it in. So if I find I need a signal/slot all of a sudden I'll just modify the class to be derived from QObject.
Those are my general rules while coding, but you can make your own based on how you feel. In the end it doesn't have much impact. :)
-
@enemyofthedawn said in Should every class in Qt derive from QObject?:
What if I don't need signals and slots in particular class and all I'm interested in is garbage collection?
You don't need QObject for garbage collection. Use
std::unique_ptr
for anon-copyablenon-sharable class, orstd::shared_ptr
for acopyablesharable class.[EDIT: Sorry, I meant "shareable", not "copyable". Here, allowing an object to be "shared" means allowing multiple entities to store pointers to the same object. --JKSH]
What are general rules when to inherit
QObject
and when not?If you want signals and slots or any of the features described in http://doc.qt.io/qt-5/metaobjects.html, consider inheriting QObject. If you don't want any of those features, don't inherit QObject.
-
@JKSH said in Should every class in Qt derive from QObject?:
Use std::unique_ptr for a non-copyable class, or std::shared_ptr for a copyable class.
I would argue here. Use the stack whenever possible (especially since
std::unique_ptr
is a stack object managing a heap allocation) and use either implicit or explicit sharing -QSharedDataPointer
withQSharedData
- for data classes (i.e. most of the stuff that falls into "copyable classes).std::shared_ptr
and the Qt equivalent has the purpose of sharing a pointer, hence the name, not to share the object/data, which is a rather rare use case. Think of what happens when you start passing shared pointers around in say a multithreaded context ... you're basically guaranteeing you're going to blow your leg off ... -
@kshegunov said in Should every class in Qt derive from QObject?:
@JKSH said in Should every class in Qt derive from QObject?:
Use std::unique_ptr for a non-copyable class, or std::shared_ptr for a copyable class.
I would argue here. Use the stack whenever possible (especially since
std::unique_ptr
is a stack object managing a heap allocation) and use either implicit or explicit sharing -QSharedDataPointer
withQSharedData
- for data classes (i.e. most of the stuff that falls into "copyable classes).Aargh, I used the wrong terminology. Rather than "copy" (as in copying the same data into multiple places and allowing each copy to be independently modified), I meant to say "share" (as in allowing multiple entities to store pointers to the same object).
With @enemyofthedawn's example,
StoreItem
looks like an identity object rather than a data/value object (see http://doc.qt.io/qt-5/object.html#qt-objects-identity-vs-value ) which is why I suggested smart pointers as an alternative to QObject inheritance for memory management. MultipleStore
objects each hold an array ofStoreItem
objects.If the owning
Store
is the only entity that reads/writes theStoreItem
s, then the array can be aQVector<std::unique_ptr<StoreItem>>
(orstd::vector
). As @kshegunov highlighted, this can also be simply aQVector<StoreItem>
. Either way, the memory occupied byStoreItem
will be released once the owningStore
is destroyed.If other objects are allowed to point to the same
StoreItem
, then theStore
can hold aQVector<std::unique_ptr<StoreItem>>
QVector<std::shared_ptr<StoreItem>>
and exposestd::shared_ptr<StoreItem>
for other entities to access the items. This way, if theStore
is destroyed while someone else is still accessing theStoreItem
, theStoreItem
will still remain usable until the last reader/writer is gone. (Although having said that, theStoreItem
's internalStore
pointer will no longer be valid, so this might be moot point) -
@JKSH said in Should every class in Qt derive from QObject?:
std::shared_ptr<StoreItem>
I don't have to return
std::shared_ptr<StoreItem>
orQSharedPointer<StoreItem>
as I'm fully aware that the owner of this object will exist when I access the item. What I do instead is simply returning pointerStoreItem*
or just a referenceStoreItem&
.No?
It's quite logical that
Store
is the owner ofStoreItem
and is responsible for freeing it and no one should ever desire to delete it outside of itWhat I would do instead is
QVector<std::unique_ptr<StoreItem>>
or maybeQVector<QScopedPointer<StoreItem>>
and returning simple raw pointer with.get()
My logic is when the store is destroyed all store items are destroyed with it.
-
@enemyofthedawn No, you definitely do not want to do that. The whole point of smart pointers like shared_ptr and unique_ptr is that they have reference counting so they can clean up for you. It's basically protecting you from having to deal with and track pointers.
By ever passing the raw pointer you are pretty much removing all the benefit of smart pointers and potentially causing crashes. I.e. if you return a
Store *
from yourshared_ptr<Store>
object and something is using that when the shared_ptr goes out of scope, it will be deleted since it doesn't know about theStore *
you sent out.If you have memory protected in a smart pointer then never use that outside the pointer unless you have a reference lock on it while you use the raw pointer. Returning a raw pointer would lose the reference since the shared_ptr would go out of scope.
That felt like I was rambling lol. Hope that made it clearer for you. :)
-
@ambershark For
std::shared_ptr
yes. I was saying aboutstd::unique_ptr
from what I saw there's nothing wrong in returning raw pointer or reference with this type of smart pointer (see here) -
@enemyofthedawn Oh yea that would be fine in unique_ptr. I must have misread that, I thought you were talking about shared_ptrs or moving them around outside of where they were created. I.e. using/storing them in a place that could have them cleaned up while still "in use".