[Interest] Handling QObject auto-deletion and signals emitted from destructors

Bo Thorsen bo at vikingsoft.eu
Fri Sep 4 09:29:20 CEST 2015


If your question is only about the generic question and not about the 
code, skip to the bottom of my reply. If it's about the actual code you 
posted, keep reading :)

Your problem is that you call a method on an object that's deleted. In 
this code:

connect(webview, &QWebView::destroyed, [this] () {
   // replicate loadFinished being fired during qwebview/webpage destruction
   emit webview->loadFinished(false);
});

This is completely wrong. When destroyed is emitted, the QWebView object 
is already "deleted" (i.e. the destructor has been called) and only the 
QObject part of it remain. Calling a method on such a half object is doomed.

I don't understand why you don't just call onLoadFinished(whatever) 
instead of trying to replicate anything. This is what you need to do.

There are some things you can do to an object in a slot that's direct 
connected to the destroyed signal. But it's a good general rule for 
anyone that you just can't do anything to it. Unless you really know 
what you are doing, you are going to get into trouble with this. And I 
don't think I've ever needed to do this. Accept that the object is gone 
and fix the code to handle this.

Another thing with your code: Why do you even want to do this? If the 
web view is destroyed, that means the entire widget is destroyed. So why 
do you need to set anything on the other widgets?

And now for the general answer: You are in trouble here. Yes, a QPointer 
is the way to track if an object is deleted or not, and I don't see how 
that's tedious. However, when you are mixing a slot connected to 
destroyed and QPointers, you start depending on the order of slots 
called. To avoid this, I'd use a queued signal or handle it in some 
other way. For this, we need actual code to help.

Bo.

Den 01-09-2015 kl. 17:06 skrev Neil Williams:
> Below is a example program which will crash when the widget is closed.
>
> This setup replicates the QWebview behaviour where it will emit the
> loadFinished signal from inside the destructor if a page is loading.
>
> I am wondering if anyone can suggest a clean way of handling this sort
> of case, where a sibling may have been deleted but is referenced in a
> connected slot of a non-deleted object.
>
> I have considered:
>
> 1. Always using QPointer and check for object validity before accessing
> in the slot. This seems like it would be somewhat tedious.
>
> 2. Using the 'context' param of QObject::connect override and splitting
> the current slot into multiple smaller slots that only access a single
> param, e.g:
>
> connect(webview,&QWebView::loadFinished, ok_widget, [this] (boolok) {
>
> ok_widget->setVisible(ok);
>
> });
>
>
> connect(webview,&QWebView::loadFinished, fail_widget, [this] (boolok) {
>
> fail_widget->setVisible(!ok);
>
> });
>
>
> This requires more boilerplate and may not be possible for more complex
> slots which need to access multiple objects.
>
>
> 3. Call to QObject::disconnect in the containing class destructor. This
> does feel a little bit like I am micro-managing the connections which
> would be nice to avoid.
>
>
> 4. Switch to manual memory management of the widgets so I can control
> destruction order.
>
>
> At the moment I am considering either 1, 3 or 4 but I would appreciate
> any other views/opinions/suggestions.
>
> Thanks.
>
> #ifndefWIDGET_H
>
> #defineWIDGET_H
>
>
> #include<QDebug>
>
> #include<QtWidgets>
>
> #include<QWebView>
>
> #include<QPointer>
>
>
> classQWebView;
>
>
> classWidget:publicQWidget
>
> {
>
> Q_OBJECT
>
>
> public:
>
> explicitWidget(){
>
>
> QVBoxLayout*layout=newQVBoxLayout();
>
>
> webview=newQWebView();
>
> ok_widget=newQWidget();
>
> fail_widget=newQWidget();
>
>
> connect(webview,&QWebView::destroyed,[this](){
>
> //replicateloadFinishedbeingfiredduringqwebview/webpagedestruction
>
> emitwebview->loadFinished(false);
>
> });
>
>
> connect(webview,&QWebView::loadFinished,this,&Widget::onLoadFinished);
>
>
> layout->addWidget(ok_widget);
>
> layout->addWidget(fail_widget);
>
> layout->addWidget(webview);
>
>
> setLayout(layout);
>
> }
>
>
> ~Widget(){
>
> qDebug()<<"Windowdestroyed";
>
> }
>
>
> privateslots:
>
> voidonLoadFinished(boolok){
>
> ok_widget->setVisible(ok);
>
> fail_widget->setVisible(!ok);
>
> }
>
>
> private:
>
> QWebView*webview;
>
> QWidget*ok_widget;
>
> QWidget*fail_widget;
>
>
> };
>
>
> #endif//WIDGET_H
>
>
>
>
> _______________________________________________
> Interest mailing list
> Interest at qt-project.org
> http://lists.qt-project.org/mailman/listinfo/interest
>

Bo Thorsen,
Director, Viking Software.

-- 
Viking Software
Qt and C++ developers for hire
http://www.vikingsoft.eu



More information about the Interest mailing list