88

Why do official examples and tutorials about the Qt library never make use of smart pointers? I only see new and delete for creating and destroying the widgets.

I searched for the rationale but I could not find it, and I don't see one myself except if it's for historic reasons or backward compatibility: not everyone wants the program to terminate if a widget constructor fails, and handling it via try/catch blocks is just ugly (even if used in few places). The fact the parent widgets may take the ownership of the children also only partially explains the thing to me, as you would still have to use delete for the parents at some level.

Alexis King
  • 43,109
  • 15
  • 131
  • 205
Martin
  • 9,089
  • 11
  • 52
  • 87
  • 10
    Qt had smart pointers much before the modern c++. And these are used in some of the projects. You don't see in that examples because QObject handles all the child / parents related issues and there life cycle. for more information about Qt smart pointers visit this ->https://wiki.qt.io/Smart_Pointers – sanjay Dec 23 '15 at 10:48
  • 2
    "you would still have to use delete for the parents at some level" - not necessarily, as the root object is usually sitting in `main()` so it will be automatically collected. – dtech Dec 23 '15 at 11:08
  • It seems QPointer can be used transparently in different contexts: i.e. it behaves like a "scoped pointer" if the referenced widget has NOT been added to a parent object before the QPointer goes out of scope, but, on the other hand, preserves the widget life if has been added to a parent.before the QPointer goes out of scope – Martin Dec 23 '15 at 11:21
  • It is not like plain pointers were deprecated or something, they are as useful as they've ever been. Contrary to what some people might say, it is still perfectly OK to use them, and in the case of Qt there are a lot of safeguards around the "sharp corners" of plain pointers. But yeah, let's stop using pointers now just because C++ finally decided to incorporate smart pointers. – dtech Dec 23 '15 at 13:43
  • 5
    @ddriver it is worth pointing out that the expert advice is not "never use raw pointers". The advice is "avoid **owning** raw pointers". That is an important distinction which you don't seem to be making. – Tim Seguine Dec 23 '15 at 13:50
  • One could ask the same question about why so much code on MSDN uses gotos, doesn't check for errors, etc. The answer is simple -- the type of code examples you find in tutorials are designed to illustrate a specific point with as little code as possible. – MrEricSir Dec 23 '15 at 19:25
  • @TimSeguine - I don't value laziness and lack of explicitness and control. The motivation behind small pointers is well within my grasp, the thing is I've already addressed those motivations in the way it suits my APIs well ahead of the standard committee. That's what I am growing to hate about C++ - changes come a little too late, and a little too ugly, clumsy and bloated. – dtech Dec 23 '15 at 21:43
  • @ddriver Is your use of pointers always exception safe? I am willing to bet it isn't. Getting memory management right means getting exception safety right, and that is not as easy since the number of possible code paths can explode in complexity. Pushing that burden of correctness onto someone who is paid to get it right on your behalf is not laziness, it is pragmatism and good engineering. – Tim Seguine Dec 25 '15 at 13:14
  • @TimSeguine - if you are betting you should specify what you are betting, otherwise it is just wishful thinking.Don't worry, I get it, you are very modern and progressing individual, as is every dedicated advocate of smart pointers. – dtech Dec 25 '15 at 13:33
  • @ddriver If taking pride in my craft and consistently making smart engineering decisions makes me an "advocate of smart pointers", then I guess I am an advocate of smart pointers. – Tim Seguine Dec 25 '15 at 13:50

5 Answers5

77

Because Qt relies on a parent-child model to manage Qobject resources. It follows the composite + Chain-of-responsibility pattern, which is used from event management to memory management, drawing, file handling, etc...

Actually, trying to use a QObject in a shared\unique pointer is overengineering (99% of the time).

  1. You have to supply a custom deleter which will call deleteLater
  2. Your qobject with parents already have a reference in the parent object. So you know that a object is not leaked as long as the parent exist. When you need to get rid of it, you can call deleteLater directly.
  3. Your QWidget without parent already have a reference in the Qapplication object. So same as point 2.

That said, you can still use RAII with Qt. For instance QPointer behaves as a weak reference on a QObject. I would use QPointer<QWidget> rather than QWidget*.

note: to not sound too fanboy, two words : Qt + valgrind.

UmNyobe
  • 22,539
  • 9
  • 61
  • 90
  • 2
    point 4. if the parent gets deleted then the shared_ptr and unique_ptr will have a dangling pointer. This is solved by the QPointer which will get cleared automatically by the QObject pointed to. – ratchet freak Dec 23 '15 at 16:59
  • For non-widget objects with no parents, is it still necessary to call `deleteLater` rather than simply `delete`ing the object? I often manage instances of QObject-derived classes using smart pointers, so I've searched for an answer to this before just to make sure I'm not doing something dangerous, and as far as I can tell the documentation does not indicate that it's *wrong* to `delete` a QObject pointer normally (even if it *is* owned by a parent object, because the destructor will remove the parent's reference). – Kyle Strand Dec 23 '15 at 18:43
  • 2
    [documentation warn you against it](http://doc.qt.io/qt-5/qobject.html#dtor.QObject). directly calling delete may cause crashes due to pending events\queued connections to the object (or its children). – UmNyobe Dec 23 '15 at 23:25
  • @UmNyobe That's true, if you delete a `QObject` from another `QThread`. The destructor of `QObject` disconnects all signals to and from it and removes pending events from its event queue automatically. Therefore, calling `delete` on a `QObject` is ok, if you do it from within its thread. That being said, you can hardly do anything wrong using `deleteLater()` except if you need immediate clean-up for some reason. – Ralph Tandetzky Jan 30 '17 at 09:20
  • @UmNyobe According to the QPointer documentation, it has nothing to do with RAII. It merely guarantees that the pointer will be 0 if someone else deltes the QObject it points to. But it never deletes the QObject itself. If you RAII, QSharedPointer should be the preferred method. – Fritz Sep 07 '17 at 17:56
30

Smart pointers to children

The smart pointer classes std::unique_ptr and std::shared_ptr are for memory management. Having such a smart pointer means, that you own the pointer. However, when creating a QObject or a derived type with a QObject parent, the ownership (the responsibility to clean up) is handed over to the parent QObject. In that case, the standard library smart pointers are unnecessary, or even dangerous, since they can potentially cause a double deletion. Yikes!

Raw pointers to orphans

However, when a QObject (or derived type) is created on the heap without a parent QObject things are very different. In that case you should not just hold a raw pointer, but a smart pointer, preferably a std::unique_ptr to the object. That way you gain resource safety. If you later hand the object ownership to a parent QObject you can use std::unique_ptr<T>::release(), like so:

auto obj = std::make_unique<MyObject>();
// ... do some stuff that might throw ...
QObject parentObject;
obj->setParent( &parentObject );
obj.release();

If the stuff you do before giving your orphan a parent throws an exception, then you would have a memory leak, if you used raw pointer to hold the object. But the code above is save against such a leak.

On a more general note

It is not modern C++ advice to avoid raw pointers all together, but to avoid owning raw pointers. I might add another modern C++ advice: Don't use smart pointers for objects that are owned by some other program entity.

Ralph Tandetzky
  • 22,780
  • 11
  • 73
  • 120
  • 4
    Yes. This. Ownership is everything. I wish the Qt documentation were a little more explicit about this; there seem to be many references to children being deleted "automatically," but not a lot of information about how orphans should be handled. – Kyle Strand Dec 23 '15 at 18:44
  • +1, in particular for the last paragraph. I've seen tons of occasions where people are relentlessly trying to use smart pointers whereever they can (in particular for parameter passing, see also [this](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-smartptrparam) core guideline. – andreee Aug 27 '20 at 11:58
12

You already answered your own question : except if it's for historic reasons/backward compatibility. A library that's as huge as QT can't assume that everyone using the library has compilers that support C++11. new and delete are guaranteed to exist in earlier standards.

However, if you do have the support to use smart pointers I would encourage to use them over raw pointers.

Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
  • however smart pointers existed before C++11 and probably before QT. Was it a bad design decision from the beginning? – Martin Dec 23 '15 at 11:00
  • 22
    err... when qt and some other libraries were designed\ implemented c++ didn't even have a standard string class. – UmNyobe Dec 23 '15 at 11:10
  • 1
    If smart pointers before C++11 means `auto_ptr`, then it was the right decision to not use it. There were no good standardized smart pointers before C++11. – Zyx 2000 Dec 23 '15 at 15:40
  • 2
    No good standardized ones, but some Qt-based ones, e.g. `QSharedPointer` and `QScopedPointer`. – Ruslan Dec 23 '15 at 16:51
  • 1
    This answer is dated because modern Qt requires C++11 support. – Mikhail Mar 11 '18 at 22:25
10

In addition to what @Jamey said:

If you design it cleverly, you may never have to use a delete on a widget. Lets say you have a main window, and you are creating an auto object of it and running that window in event loop. Now rest all of the items in this widget can be added as its children. And since you are adding them to this MainWindow directly/indirectly as child, when you will close this main window everything will be taken care automatically. Just you have to ensure that all the dynamic objects/widgets you have created are children/grandchildren of the MainWindow. Hence no need of a explicit delete..

PRIME
  • 1,058
  • 7
  • 21
  • 2
    You ll have to add each child to the main window as soon as you create it or at least before anything that can throw, or the thing does not work, a constraint that I'd like to avoid to remember – Martin Dec 23 '15 at 10:58
  • 2
    @Martin nothing throws in Qt apps normally (unless one is a real fan, that is), so come on :) – mlvljr Dec 17 '16 at 01:13
5
  • QObject has a parent defined and the tree like structure of the program permits to manage memory quite effectively.

  • Dynamism in Qt breaks that nice ideal, e.g. passing a raw pointer around. One can easily end-up holding a dangling pointer , but that's a common issue in programming.

  • The Qt smart pointer , actually a weak reference, is QPointer<T>
    and provides some of the STL candy.

  • One can also mix with std::unique_ptr and the like , but it should be used only for non-Qt machinery in your program.

g24l
  • 3,055
  • 15
  • 28