2
class A : public QObject {
  A() : b(this) {} // !


  class B : public QObject {
    B(QObject* parent)
  };
  B b;
}

Should I setup parent if child object is not dynamic? what a difference between both cases?

What's better and what a difference between?

class A : public QObject {
  A() : b(new B(this)) {} // !


  class B : public QObject {
    B(QObject* parent)
  };
  B* b;
}

or

class A : public QObject {
  A() : b(new B()) {} // !


  class B : public QObject {
    B()
  };
  smart_ptr<B> b;
}
fhdnsYa
  • 413
  • 5
  • 12

2 Answers2

2

QObject parentage and storage duration are orthogonal issues and should be addressed separately.

You cannot move a QObject holding other QObjects to another thread, unless all the owned objects have the owner set as a parent. Thus, by not setting the parent, you're prematurely limiting the functionality of the parent class.

In modern C++, child QObjects with dynamic storage duration should be held via a resource manager. Such a manager can be a smart pointer, or simply the owning object. Recall that a QObject is also, implicitly, a QObject container. Because of that, it's not even necessary to have an explicit member pointer to the child object - say if you're only needing to refer to the object directly during construction of the owner.

Generally speaking, by having any members with dynamic storage duration, you're prematurely pessimizing unless their constructors are very expensive and you would want to delay construction until a later point.

So, if you're not using the PIMPL idiom, then all members should have automatic storage duration in the object itself:

// A.h
class A : public QObject {
  Q_OBJECT
  QSerialPort m_port { this };
  QThread m_thread { this };
  ....
};

Otherwise, they belong in the PIMPL:

// A.h
class APrivate;
class A : public QObject { ... };

// A.cpp
#include "A.h"
class APrivate {
public:
  A * const q_ptr;
  QSerialPort m_port { q_ptr };
  QThread m_thread { q_ptr };  
  APrivate(A * q) : q_ptr(q) {}
};

It should also be pointed out that using pointers to forward-declared incomplete types in order to "speed up" compilation or "decrease dependencies" is an anti-pattern. If you are willing to expose implementation details in a header file, just hold all the members you can by value - as in the first example above. If you're worried about excessive dependencies and want to hide your implementation, use the PIMPL. The "middle road" of pointers-to-forward-declared-classes forces extra dynamic storage allocations upon you and is thus an inflexible monstrosity that helps nothing and no-one.

// DO NOT WRITE CODE LIKE THIS!!
class QSerialPort;
class QThread;
class A : public QObject {
  Q_OBJECT
  QSerialPort * m_port;
  QThread * m_thread;
  ...
};
// DO NOT WRITE CODE LIKE THIS!!
Community
  • 1
  • 1
Kuba hasn't forgotten Monica
  • 88,505
  • 13
  • 129
  • 275
1

The parent/child mechanism is a little more than just deleting the object when it's parent is destroyed. Child objects for example will always run on the same thread as their parent, and if the parents thread is changed, the childs will move, too. But just one of many examples. You won't have these features if you are using smart_ptr<B> b. The equivalent in Qt for this would be QScopedPointer. So it's better to use the QObject parent/child mechanism, if possible. More information about the whole QObject-parent-child-mechanism, see Object Trees & Ownership

And regarding the difference between pointer or stack: Most QObjects aren't copyable and can't be "move-assigned". In such cases, you will need the pointer to "exchange" the child object. But except of that, it's more a question of style. I personally like the pointer-approach more. And even if you are using the "stack-version", you can still pass a parent, to make use of all the other features.

But most important: It seems you forgot to pass parent to the QObject-constructor! (Correct me if you just left it out to simplify the code-blocks). If you don't do this, your object will not become a child of it's parent:

class A : public QObject {
  A(QObject *parent = NULL) : 
    QObject(parent),//Here, because A may become a child of another object some time
    b(new B(this))
  {}


  class B : public QObject {
    B(QObject *parent = NULL) : 
      QObject(parent)//And here it's neccessary
    {}
  };
  B* b;
}
Felix
  • 6,217
  • 1
  • 26
  • 50