[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kfm-devel
Subject:    Re: Review Request 117478: Convert dolphin (frameworks) to Qt5 signal/slot syntax
From:       Alexander Richardson <arichardson.kde () googlemail ! com>
Date:       2014-04-16 18:17:54
Message-ID: CA+Z_v8rYN7qF1XEM+Yh1XB0Og=-LqwmNQybOev_Gjm=W6jAufA () mail ! gmail ! com
[Download RAW message or body]

2014-04-15 19:23 GMT+02:00 Olivier Goffart <olivier@woboq.com>:
> On Tuesday 15 April 2014 09:47:13 Thiago Macieira wrote:
>> Em ter 15 abr 2014, =C3=A0s 02:36:58, Alexander Richardson escreveu:
>> > I didn't see see Thiago's message since I am not subscribed to kfm-dev=
el.
>> > From what I saw in the Qt documentation I always assumed they were
>> > equivalent (except for not allowing default arguments in the slot), wh=
ich
>> > other differences exist?
>>
>> The major difference is the problem of what gets called when the target
>> object is being destroyed. Olivier has more details.
>>
>> Olivier?
>
> In general, if it compiles, there is no difference.
>
> But there is some things to take care of:
> Using the string syntax, signals and slot behave as virtual, which means =
that
> the connection will use signals or slots in the most derived class with t=
he
> same name if one exist even while connecting to the base class.  While th=
e Qt5
> syntax really connects to the slot of the class specified.  In order to g=
et
> the same behaviour, you need to mark the slot as virtual explicitly.
>
> And as Thiago mentioned there is also the problem that if a signal is emi=
tted
> from a destructor and is connected to a slot of the object being destroye=
d,
> the slot will be called on the partially destroyed object.  This is more =
like
> a bug but i have no clear idea how to fix it.
>
> --
> Olivier
>
> Woboq - Qt services and support - http://woboq.com - http://code.woboq.or=
g

Ah yes, I completely forgot about slots being pseudo-virtual functions.

Would comparing the value of metaObject() be a possible solution to
calling slots from partially destructed objects?
Not sure if my approach in this test here is too naive, but it seems
to work. Maybe it breaks with other compilers than GCC or multiple or
virtual inheritance, I don't know that. To me it seems that the slot
is not invoked with the old syntax because the slot is not found
inside metaObject(), but maybe I am wrong, I didn't dig too deeply
into the metaobject source code.

In what I gathered from
http://woboq.com/blog/how-qt-signals-slots-work-part2-qt5.html a
QMetaObject* could be stored in QSlotObjectBase and compared to
receiver->metaObject() in order to determine whether the object is
being destroyed. Maybe there is a better place to store it as well
since adding another pointer to each signal slot connection sounds
expensive. Maybe inside QObjectPrivate, not sure if that is possible.

I think this should work since the destructor changes the vtable
pointer from what I found in my testing and googling, but I can't
quote the standard on it.

Assuming this fix for calling slots from the destructor after the
object has been destroyed the automatic conversion should be safe,
right?
Of course there needs to be a static analysis tool that makes sure
that no slots with the same name and parameter as a base class slot
are declared if they are not virtual, but that shouldn't be too
complicated using clang.

Regards,
Alex

["main.cpp" (text/x-c++src)]

#include "main.h"

int main()
{
    Derived* d = new Derived();
    QMetaObject::Connection cOld = QObject::connect(d, SIGNAL(sigOld()), d, SLOT(oldSyntax()));
    QMetaObject::Connection cNew = QObject::connect(d, &Derived::sigNew, d, &Derived::newSyntax);
    emit d->sigOld();
    emit d->sigNew();
    delete d;
    return 0;
}

["main.h" (text/x-chdr)]

#ifndef MAIN_H
#define MAIN_H

#include <QObject>
#include <cstdio>

class Base : public QObject {
    Q_OBJECT
public:
    Base(const QMetaObject* meta) : origMetaObj(meta) {}
    ~Base() {
        printf("~Base(): metaobj = %s\n", metaObject()->className());
        emit sigOld();
        emit sigNew();
        printf("deleted Base\n");
    }
signals:
    void sigOld();
    void sigNew();
protected:
    const QMetaObject* origMetaObj;
};

class Derived : public Base {
    Q_OBJECT
public:
    Derived() : Base(&staticMetaObject), value(new int(3)) {
        printf("Derived: value = %p\n", value);
    }
    ~Derived() {
        printf("Derived metaobj = %s\n", metaObject()->className());
        delete value;
        value = (int*)0xdeadbeef;
        printf("deleted Derived\n");
    }
public slots:
    void newSyntax() {
        if (metaObject() != origMetaObj) {
            qWarning("newSyntax() called from destructor!");
            return;
        }
        printf("newSyntax(): value = %p, class name = %s\n", value, metaObject()->className());
    }
    void oldSyntax() {
        if (metaObject() != origMetaObj) {
            qWarning("oldSyntax() called from destructor!");
            return;
        }
        printf("oldSyntax(): value = %p, class name = %s\n", value, metaObject()->className());
    }
private:
    int* value;
};

#endif // MAIN_H


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic