Irisciences
Irisciences

Reputation: 308

Qt and pointers

I'm new to Qt and I'm reading several Qt Projects to get the basics. While browsing the different classes it seems that pointers to QWidget are always used.

Exemple :

class ExempleWidget : public QWidget
{
    Q_OBJECT
public:
    ExempleWidget();
    ~ExempleWidget();

private:
    QPushButton * m_stopButton;
    QPushButton * m_playButton;

    QHBoxLayout * m_hBoxLayout;
    QVBoxLayout * m_vBoxLayout;
};

Is there any reason for using pointers for 'QPushButton' *'QHBoxLayout'* etc. ? Can we just use values so we don't have to bother with 'new' and 'delete'? Well I know we can but is it a good way to do it?

E.g.

private:
    QPushButton m_stopButton;

EDIT :

All answers seems to point out the hierarchy between Qt classes. It's a good enough reason for me and I don't doubt of the point but let's say that there is no link between the widgets of my class (*m_stopButton* and *m_playButton*).

I can safely declare them as values in this case, can't I? When the class will be deleted, the members will be deleted too so pointers or not we will have the same behavior.

Upvotes: 8

Views: 4114

Answers (5)

You'd want to use the pointers when you wish have full control over the object's lifetime. For example

  1. If you want to construct a class member at some point after the initialization list in the constructor has been processed.

  2. If you want to destruct a class member at some point before the compiler-generated destructor epilogue runs.

It is perfectly safe not to use the pointers when you are OK with the compiler constructing and destructing the object instances for you.

Raw pointers turn out to be error-prone whenever they own the resource they point to: it's an error to forget to delete the owned resource, to delete the resource multiple times, or to dereference an already-deleted resource.

Use of raw pointers (as opposed to smart pointers) that do not own the resource - when the resource will be freed by someone else - may still be a case of premature optimization. The use of raw pointers is prone to turn "small" code changes into resource leaks:

class X : public QObject {
  QObject * a;
public:
  // OK
  X() : a(new QObject(this)) {}
  // an error - we need to add a destructor that deletes a
  X() : a(new QObject) {}
}

class X : public QObject P
  QScopedPointer<QObject> a;
public:
  // Both OK
  X() : a(new QObject(this)) {}
  X() : a(new QObject) {}
};

The smart pointers - C++11's std::unique_ptr, Qt 4.6's QScopedPointer - guarantee that the deletion always happens, and that access to a deleted resource is equivalent to a null pointer dereference and thus nominally caught and signaled by the processor hardware.

In C++, the order of construction and destruction of class members and automatic variables is fixed. In the examples below, the construction order is always a then b, and the destruction order is always b then a. This is very important.

class C {
  A a;
  B b;
};

void test() {
  A a;
  B b;
}

Thus, the following code is valid and behaves correctly under at least Qt 3, Qt 4 and Qt 5, unless specified otherwise.

class C : public QWidget {
  QWidget a;
  QLabel b;
public:
  C(QWidget * parent = 0) : QWidget(parent), a(this), b(&a) {}
}

// Qt 4.6 & up only
class C : public QWidget {
  QScopedPointer<QWidget> a;
  QScopedPointer<QLabel> b;
public:
  C(QWidget * parent = 0) : QWidget(parent), 
                            a(new QWidget(this)),
                            b(new QLabel(a.data())) {}
};

// C++11 only
class C : public QWidget {
  std::unique_ptr<QWidget> a;
  std::unique_ptr<QLabel> b;
public:
  C(QWidget * parent = 0) : QWidget(parent), 
                            a(new QWidget(this)), 
                            b(new QLabel(a.data())) {}
};      

void test() {
  QWidget c;
  QWidget a(&c);
  QLabel b(&a);
}

In all cases, the construction order is: c, a, b; the destruction order is: b, a, c.

Upvotes: 6

Stack Overflow is garbage
Stack Overflow is garbage

Reputation: 247899

Qt is basically designed as C++ anno 1996 or so (or very Java-esque, if you will). Lots of pointers, lots of inheritance.

Of course one reason they frequently use pointers is that inheritance is virtually everywhere, and it avoids any slicing-related issues.

Another reason is that Qt has a strong convention that memory management is handled by giving every object a parent, so that when the parent is destroyed, it calls delete on its children.

If you declare your object as a local object instead of a pointer to something allocated with new, then you have to be careful about either not giving it a parent, or otherwise ensuring that it goes out of scope before its parent to ensure delete is never called.

Upvotes: 5

UmNyobe
UmNyobe

Reputation: 22890

Yes there is a reason. All subclasses of QObject can be put in a hierarchy using the parent attribute. It is very useful because It allows an action on a QObject to be propagated to all the children hierarchy. One of these actions is show or hide for widgets, another is object destruction.

When you delete a QObject (ie a Qwidget too), all of his children are also deleted. as the doc says

Warning: All child objects are deleted. If any of these objects are on the stack or global, sooner or later your program will crash

Furthermore you can move objects to other threads. In order to do that you need those object to be on a memory region which is available to all threads in a process. The stack is for a single thread, so it not appropriate.

On a pure language perspective, You only have the constructor

QObject::QObject( QObject * parent = 0 );

If you provide a value to parent different to NULL, this value should have a lifetime greater than the object being constructed. Otherwise It might use an invalid reference.

Basically they had different mechanisms they wanted to put in place, and with different constraints (including backward compatibility), it is the one they chose.

Upvotes: 2

MSalters
MSalters

Reputation: 179779

The reason is historical. In older Qt versions, when you pass the parent widget to the constructors of the member widgets, the parent QWidget::~QWidget calls delete on the child widgets.

In current Qt versions a check has been added to see if the child widget has already been deleted, which means you can now make them ordinary members.

Upvotes: -1

Jepessen
Jepessen

Reputation: 12415

Because in constructor you can give them a parent, so when parent is deleted they are deleted too automatically.

There can be also other reasons, depending on the project (like creating and destroying methods depending on class logic).

Upvotes: 3

Related Questions