5

I'm trying to update a small utility application to a more modern C++ fashion, but I'm having problems using some Qt objects with std::shared_ptr, especially those that receive some other QWidget as a constructor argument.

For example:

private:
    std::shared_ptr<QWidget> centralwidget;
    std::shared_ptr<QVBoxLayout> verticalLayout;

public:
    void setupUi(QMainWindow *MainWindow) // this pointer is a .get() from a shared_ptr
    {
        centralwidget = std::make_shared<QWidget>(new QWidget(MainWindow)); // compiles fine
        verticalLayout = std::make_shared<QVBoxLayout>(new QVBoxLayout(centralwidget.get())); // does not compile
    }

The compile error is:

Error 1 error C2664: 'QVBoxLayout::QVBoxLayout(QWidget *)' : cannot convert parameter 1 from 'QVBoxLayout *' to 'QWidget *' e:\microsoft visual studio 11.0\vc\include\memory 855

I cant seem to understand this error, I'm not converting anything, I'm just trying to create a QVBoxLayout object and passing a QWidget as its parent (like i would do with raw pointers).

2 Answers 2

17

In general, I try to avoid using shared_ptr for Qt GUI objects, since Qt already provides its own memory management mechanism. Each QObject possibly has a parent, and when this parent dies he deletes all of its children. A shared_pointer is not required here and doesn't give you any added value: you could perfectly use a raw pointer without creating a memory leak.

Generally speaking, if the QObject's parent dies before the last shared_ptr instance is deleted, you'll quickly get into troubles since the object will be deleted a second time when the last shared_ptr will be destroyed. That's not the case here, but be careful :)

Sign up to request clarification or add additional context in comments.

4 Comments

thanks. actually just a few minutes ago when i was testing everything more thoroughly it did start crashing on a few cases. debug said: "memory violation accessing object destructor" so yeah i think that is the case, so i just returned to my old implementation (with raw pointers) using the Qt object manager. oh well, at least it was a good exercise i suppose :) thanks again.
Want to add one more issue with std::shared_ptr<QObject>: destroying QObject in a thread different that QThread dispatching events to this particular instance is not safe. You need to play a tricky game with custom deleter calling deleteLater and try to avoid shared pointers outliving the thread object belongs to.
I can't stress enough the second paragraph of this answer. Mixing std::shared_ptr<QObject> and Qt-ish parent-child ownership mechanism is really dangerous! It leads to crashes which you exactly described. I would like to warn everybody against holding objects derived from QObjects in std::shared_ptr. This is safe only if you are sure that the QObject does not have and will never have a parent or that the shared pointer is destroyed before the parent, but it is very difficult to enforce especially in a large codebase. And it is impossible for QWidgets which always have parents.
@V.K. can't you still do std::shared_ptr<QObject>(new myQObj(parent), [](auto) {})? That is, use a nop deleter?
5

The arguments to std::make_shared are passed to the constructor of the class you're instantiating. So basically what you are doing is equivalent to:

new QVBoxLayout(new QVBoxLayout(centralwidget.get()))

I think what you are trying to do is :

centralwidget = std::make_shared<QWidget>(MainWindow);
verticalLayout = std::make_shared<QVBoxLayout>(centralwidget.get());

Have a look at the documentation of std::make_shared (for example here). The whole point of this function is to allocate the reference count near the object instance in memory, so you have to let it do the allocation for you.

2 Comments

thank you so much this was starting to give me a headache. so when Herb Sutter says there's not a single "new" keyword on modern c++ he wasn't kidding :p once again thanks, the utility is working and 0 memory leaks :)
Please don't skip the answer of @Frédéric Terrazzoni below for a commentary about the use of smart pointer with Qt.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.