Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

C++11 standard and Qt5 default GUI



  • Whenever I read about pointers on forums and blogs, it really seems you shouldn't use raw pointers but smart pointers instead. From my perspective, I tend to use vectors, lists and the Qt equivalents such as QVector and QList. I am studying how QSharedPointers work too. However, I can't help noticing that the default GUI application created in Qt Creator has a default User Interface, and that user interface is dynamically allocated using new and deleted in the main window destructor using delete.
    Now, my simple question is: why? Shouldn't you use something like QUniquePointer or QSharedPointer, which smoothly take care of deletions?


  • Lifetime Qt Champion

    Hi
    In a perfect work they should use a smart pointer but please keep in mind that Qt has to work across
    many platforms and not all compilers on those platform did support c++11 etc. so
    I guess they used the easy way.
    From 5.6 they will start to use new language features so it might change later on.

    Also, before you use smart pointers all over Qt. It has a ownership system where parent deletes children
    so often a smart pointer is not needed.

    For your own data, yes, plesae use all the new smart pointers. Makes more robust code by far.



  • Thank you for answering, @mrjj. I am well aware of the Qt mechanism in which all objects get deleted when their parents get deleted (I find this feature amazing).

    Also, in many applications I use QThreads and Worker threads. However, a worker thread can't have a parent, otherwise you can't move it to another thread. And the thread itself has no parent. Many tutorials (even the official ones) make use of deleteLater() function.
    I have code like this:

    thread = new QThread;
    rrtcomputer = new RRTComputer(...initialization parameters...);
    rrtcomputer->moveToThread(thread);
    
    connect(thread, &QThread::started, rrtcomputer, &RRTComputer::start);
    connect(rrtcomputer, &RRTComputer::newData, &processingInterface, &ProcessingInterface::processEdge);
    connect(&processingInterface, &ProcessingInterface::updatedData, this, &GraphicalUserInterfaceWindow::updateGUI);
    connect(rrtcomputer, &RRTComputer::newPath, &processingInterface, &ProcessingInterface::processPath);
    connect(rrtcomputer, &RRTComputer::finished, &processingInterface, &ProcessingInterface::lastUpdate);
    connect(rrtcomputer, &RRTComputer::finished, thread, &QThread::quit, Qt::DirectConnection);
    thread->start();
    

    Since this code is in the mainWindow GUI, should user close the window, worker thread gets stopped and deleted in the destructor like this:

    rrtcomputer->requestStop();
    thread->wait();
    
    delete thread;
    delete rrtcomputer;
    delete ui;
    

    Shall I use QUniquePointer for both thread and rrtcomputer instead of a raw pointer?


  • Lifetime Qt Champion

    well you could if they are members of Main or some other object that has long life.
    Then you are sure they are deleted with the it.

    Where do you have doc for QUniquePointer ? I cannot find it.
    Im using c++ unique_ptr so want to see the difference.
    Also I wonder if u ment QScopedPointer



  • @mrjj Sorry, I meant std::unique_ptr and I thought there was the equivalent in Qt with the same name.
    If I use a QScopedPointer for a member that is global in a class (i.e. it is defined in the .h file), does it get deleted when the class destructor is called?
    Another thing: if I have a method that dybnamically allocate an object and return that pointer, how shall I use it with QScopedPointer? Or shall I use QSharedPointer instead?
    For example:

    QScopedPointer<MyObject> pointerToMyObject = allocatePointer();
    

    being allocatePointer() like:

    QScopedPointer<MyObject> allocatePointer()
    {
        QScopedPointer<MyObject> pointer(new MyObject());
        // some processing on 'pointer'
        return pointer; 
    }
    

    But I do think at the end of the function pointer will be deleted since it gets out of scope. Shall I use a QSharedPointer instead?


  • Lifetime Qt Champion

    hi
    yes QScopedPointer is for deleting
    allocated object when QScopedPointer goes out of scope.
    Like in a function where there can be multiple exit location for handling errors or exceptions.

    Its not so good for returning from a function as it goes out of scope and get deleted.

    In such cases std::unique_ptr is better - as its more about who owns the object than auto clean up.

    This was a good read (in my opinion)
    https://www.safaribooksonline.com/library/view/effective-modern-c/9781491908419/ch04.html


  • Moderators

    I think these sorts of questions are best answered when you inspect the reasons for some of the guidelines out there.
    For starters: why are smart pointers so widely recommended these days? Well, mostly because of this code:

    Stuff* foo = new Stuff;
    foo->doSomething(); //if this throws an exception you've got a leak
    delete foo;
    

    To avoid this we're recommending this instead:

    SomeSmartPointer foo(new Stuff);
    foo->doSomething(); //ok to throw
    

    So what's inside SomeSmartPointer? To simplify, this:

    template<typename T>
    struct SomeSmartPointer
    {
        T* foo;
        SomeSmartPointer(T* ptr) : foo(ptr) {}
        ~SomeSmartPointer() { delete foo; }
    };
    

    Now lets change some names:

    struct MainWindow
    {
        Ui::MainWindow* ui;
        MainWindow() : ui(new Ui::MainWindow) {}
        ~MainWindow() { delete ui; }
    };
    
    
    MainWindow mw;
    mw.doStuff(); //ok to throw, ui will be cleaned up anyway
    

    Huh, how about that? Yes, MainWindow is now a smart pointer of sorts. There's no need to use another smart pointer like there's no need to use std::unique_ptr<std::unique_ptr<Stuff>>. One is enough. Basically anything that allocates resources, takes "ownership" of it and cleans them up in the destructor is sorta smart pointer. There's no risk in case of an exception because the destructor will clean up. Unless of course the destructor throws, in which case the problem is really the throwing destructor, not usage of any smart pointers.

    Some might say: "but but but what if I forget to call delete in the destructor?". Sigh... Then you have a bug. Simple. But ok, lets just pretend for a while that smart pointers are free ride and there's no cost attached. Fine. There's nothing stopping you from using a smart pointer:

    struct MainWindow
    {
        std::unique_ptr<Ui::MainWindow> ui;
        MainWindow() : ui(new Ui::MainWindow) {}
    };
    

    That's fine. You won't forget your delete now. One (possibly minor) problem is that you now have to include a header for that smart pointer in your header. It might not seem a biggie, but trust me - these sorts of things become problems 10 years later when your project has grown, and I've seen my share of these.

    Ok, but since you're using Qt anyway you might want to use a a Qt's smart pointer. Fine. QScopedPointer destroys its pointee when it is destroyed. The scope of a member is the class that hosts it, so yeah, you can use QScopedPointer just the same:

    struct MainWindow
    {
        QScopedPointer<Ui::MainWindow> ui;
        MainWindow() : ui(new Ui::MainWindow) {}
    };
    

    Still fine. A side note here - despite the name QScopedPointer it can just as well be used witout any scoping, e.g.:

    QScopedPointer<Foo>* ptr = new QScopedPtr<Foo>(new Foo);
    delete ptr;
    //we're still in scope but neither the pointer nor the pointee exist
    

    But I digress.

    No what about this other case - a pointer factory function. Qt does not really use much of these. True, it returns a lot of pointers (like QMenu->addAction()), but it usually retains ownership of these pointers and just hands out a non-owning raw pointer. There's nothing wrong with that and it's still the recommendation these days, as it's the cheapest way to do this.

    If you shift the question to your own, non Qt factory functions, then yes - the semantic way of doing this is with smart pointers.
    Use std::unique_ptr for passing ownership or std::shared_ptr/QSharedPointer for sharing it. Note that there's no real counterpart of std::unique_ptr in Qt. QScopedPointer is not it. Don't use it for that. Why? Because it has no move semantics like std::unique_ptr does.

    When you return a std::unique_ptr from a function the result is moved into the std::unique_ptr in the outer scope (well, actually RVO kicks in, but lets just pretend for a moment that compilers are really dumb :) ). QScopedPointer has no move or copy constructor, so this will compile and work fine:

    std::unique_ptr<Foo> makeMeAFoo() {
        return std::make_unique<Foo>();
    }
    
    std::unique_ptr<Foo> foo_ptr = makeMeAFoo();
    

    while this won't compile:

    QScopedPointer<Foo> makeMeAFoo() {
        return QScopedPointer<Foo>(new Foo());
    }
    
    QScopedPointer<Foo> foo_ptr = makeMeAFoo();
    

    You might be tempted to use QSharedPointer in this case and it would work, but remember that QSharedPointer, just like std::shared_ptr, is a lot heavier construct, as sharing in a multi-threaded world is a "far from 0" overhead thing. So the point is: don't use QSharedPointer just because it's smart. Use it only when you want to actually share something. A ui pointer in a widget class is not one of those things.



  • The advice to not use raw pointers is an attempt to say "make sure about ownership, do not leak resources". I.e. the full (proper) advice would be something like "don't use raw pointers unless there's something else taking care of ownership". This "something else" does not exist in plain C++, so people get lazy and drop the "unless ..." part (and other people read the abbreviated form, don't understand where it comes from, and develop an irrational fear of plain pointers).

    In a Qt context, QObject parents take ownership of their children, so ownership is handled for all non-toplevel QObjects, i.e. the unqualified advice is plainly wrong. For the remaining few toplevel QObject items it is mostly a matter of taste whether they are put into a QScopedPointer (takes an extra #include + produces a template instantiation) or are deleted manually (needs typing the delete). Qt Creator's choice minimizes the impact of #includes. If that's not of importance, second best choice would be to move the #include "ui_....h" from the .cpp to the .h and make the Ui::Class a proper class member, not a pointer. Third choice would be QScopedPointer or std::unique_ptr.


  • Qt Champions 2017

    @alogim

    Also, in many applications I use QThreads and Worker threads. However, a worker thread can't have a parent, otherwise you can't move it to another thread.

    That's not how it works. QThread is a QObject that manages a thread not the thread itself, it can have a parent. Threads are oblivious to such things as objects or object relationships.

    A thread has an entry point (a function much like main()) and a stack, nothing more, nothing less. Any object you create in the thread's stack is managed by the thread itself, stacks are not shared between the running threads. This doesn't mean that a thread can't modify another thread's stack, it only means that the stack's push and pop (creation and destruction of variables/objects) are done in one thread alone (the one that owns the stack).

    Anything you create in the heap is shared between all the threads in the process' address space, and is managed by no thread - you manage the heap with new and delete; there's no automatic creation/destruction of objects there. The heap is just that - a big pile of memory blocks (whence the name).

    When you call QThread::start it invokes the OS' API which spawns a new thread and in the "thread main" QThread::run is called. QThread::run by default calls QThread::exec to start the (thread) event loop. The QThread object itself in fact is just happily sitting in either the stack of another thread (if you created it on the stack), or in the heap. It doesn't much care that one of it's functions is called from another thread. So this is the obvious reason why you need to synchronize your threads manually (with mutexes and semaphores) if you reimplement QThread::run.

    Shall I use QUniquePointer for both thread and rrtcomputer instead of a raw pointer?

    Nope, you should connect the appropriate signals and slots (and not delete explicitly an object that "lives" in another thread):

    connect(thread, &QThread::finished, rrtcomputer, &RRTComputer::deleteLater);
    

    On a related note, this:

    connect(rrtcomputer, &RRTComputer::finished, thread, &QThread::quit, Qt::DirectConnection);
    

    shouldn't be connected directly. Just use the default parameter (Qt::AutoConnection).

    That's for threads. It's an extensive and somewhat complicated topic. Now back to your original question:
    There are quite a lot of pointer wrapper classes in Qt and each has it's own purpose. It's generally not advised to just use QSharedPointer for everything.

    Now, my simple question is: why? Shouldn't you use something like QUniquePointer or QSharedPointer, which smoothly take care of deletions?

    It should use (if one of the wrappers is preferred) a QScopedPointer, which is a thin wrapper around raw pointers and makes sure the managed object is deleted when the managing QScopedPointer goes out of scope. However, since the form object (I believe that's what you're referring to) is created only in the constructor and freed only in the destructor (i.e. it persists through the whole lifetime of the containing object) it can be easily managed without the wrapper as well, there's no need for the overhead.

    A note:
    There's no QUniquePointer class.

    In a perfect work they should use a smart pointer but please keep in mind that Qt has to work across
    many platforms and not all compilers on those platform did support c++11 etc.

    It shouldn't, and this has nothing to do with C++11 (see above).

    Kind regards.



  • @Chris-Kawa said:

    why are smart pointers so widely recommended these days?

    I believe you are right, but important part of why you are right is missing.
    Smart pointers in Qt existed way before C++11 and they would be used if it had sense.
    It does not only partially because QObject child is deleted by parent.
    Main case when smartpointers shine - simplification when providing exception safety.

    Qt does not guarantee exception safety and there is no way to recover from exception
    if it is thrown within Qt code.

    The code below only look like safe
    MainWindow mw;
    mw.doStuff(); //ok
    In reality it is mostly likely is not.
    For example if it uses Qt creator and ui generated code below.

    class Ui_UCModelerClass
    {
    public:
    QDockWidget *dockWidget_Floors;
    QWidget *dockWidgetContents_Floors;
    ...
    void setupUi(QMainWindow *UCModelerClass)
    {
    dockWidget_Floors = new QDockWidget(UCModelerClass);
    dockWidgetContents_Floors = new QWidget();
    }
    }

    Above code could be modified to be exception safe manually,
    but it can't be done to Qt internals, so
    you can only hope that exception would not be thrown
    within Qt classes.
    If it is, the best you can do - exit.

    Detailed notes can be found at http://doc.qt.io/qt-5/exceptionsafety.html


  • Qt Champions 2017

    @alex_malyu
    The original post is some 2 months old. So I wrote a whole lot of a post in reply to the original question ... well didn't my ears burn, when I noticed the post time ... I felt like a complete idiot. :)