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 heaviness QObject inheritance adds.

    Let's say I have class that depends on another class for example Store and StoreItem. StoreItem constructor is defined as follows:

    StoreItem(Store *store)

    it has a member pointer to Store so you know to which store it belongs. The Store class has QVector<StoreItem*> or QVector<QSharedPointer<QStoreItem*>> inside and functions like StoreItem *addItem(...).

    Should StoreItem be a QObject class or non qt class?
    Should Store be a QObject class?

    What are general rules when to inherit QObject and when not?


  • Moderators

    @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. :)


  • Moderators

    @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 a non-copyable non-sharable class, or std::shared_ptr for a copyable sharable 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.


  • Qt Champions 2017

    @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 with QSharedData - 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 ...


  • Moderators

    @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 with QSharedData - 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. Multiple Store objects each hold an array of StoreItem objects.

    If the owning Store is the only entity that reads/writes the StoreItems, then the array can be a QVector<std::unique_ptr<StoreItem>> (or std::vector). As @kshegunov highlighted, this can also be simply a QVector<StoreItem>. Either way, the memory occupied by StoreItem will be released once the owning Store is destroyed.

    If other objects are allowed to point to the same StoreItem, then the Store can hold a QVector<std::unique_ptr<StoreItem>> QVector<std::shared_ptr<StoreItem>> and expose std::shared_ptr<StoreItem> for other entities to access the items. This way, if the Store is destroyed while someone else is still accessing the StoreItem, the StoreItem will still remain usable until the last reader/writer is gone. (Although having said that, the StoreItem's internal Store 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> or QSharedPointer<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 pointer StoreItem* or just a reference StoreItem&.

    No?

    It's quite logical that Store is the owner of StoreItem and is responsible for freeing it and no one should ever desire to delete it outside of it

    What I would do instead is QVector<std::unique_ptr<StoreItem>> or maybe QVector<QScopedPointer<StoreItem>> and returning simple raw pointer with .get()

    My logic is when the store is destroyed all store items are destroyed with it.


  • Moderators

    @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 your shared_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 the Store * 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 about std::unique_ptr from what I saw there's nothing wrong in returning raw pointer or reference with this type of smart pointer (see here)


  • Moderators

    @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".


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.