Discussion:
[Interest] Best way to QObject-wrap simple objects
K. Frank
2013-02-19 13:19:18 UTC
Permalink
Hello List!

Sometimes I have a simple class, maybe a POD, that I want to
pump through a queued signal-slot connection. As I understand
it, I need a QObject to do that. So I wrap my class in QObject.

What are some good idioms for this? What is the most parsimonious
approach?

Here's one method I've used:


wrapped_pod.h:

#include "pod.h"
#include <QObject>
#include <QMetaType>

class WrappedPOD : public QObject, public POD {
Q_OBJECT
public:
WrappedPOD() {}
WrappedPOD (const WrappedPOD &wp) : POD(wp) {}
WrappedPOD (const POD &p) : POD(p) {}
~WrappedPOD() {}
};


(A comment: I was a little surprised that I seem to need to define
the constructors. I would have thought that the c++ defaults would
have sufficed.)

Any thoughts on other, better ways to achieve this goal? Or is there
an approach I can use that avoids wrapping the object in the first place?

I imagine that this is not an uncommon need, so I imagine that there
is some standard practice I can learn from.


Thanks.


K. Frank
Samuel Gaist
2013-02-19 13:24:44 UTC
Permalink
Hello,

IIRC you don't,

You have to Q_DECLARE_METATYPE your POD, qRegisterMetaType it and maybe (depends on your use case) add the in/out stream operators (only if you need to load and store in a QVariant).

Hope it helps
Post by K. Frank
Hello List!
Sometimes I have a simple class, maybe a POD, that I want to
pump through a queued signal-slot connection. As I understand
it, I need a QObject to do that. So I wrap my class in QObject.
What are some good idioms for this? What is the most parsimonious
approach?
#include "pod.h"
#include <QObject>
#include <QMetaType>
class WrappedPOD : public QObject, public POD {
Q_OBJECT
WrappedPOD() {}
WrappedPOD (const WrappedPOD &wp) : POD(wp) {}
WrappedPOD (const POD &p) : POD(p) {}
~WrappedPOD() {}
};
(A comment: I was a little surprised that I seem to need to define
the constructors. I would have thought that the c++ defaults would
have sufficed.)
Any thoughts on other, better ways to achieve this goal? Or is there
an approach I can use that avoids wrapping the object in the first place?
I imagine that this is not an uncommon need, so I imagine that there
is some standard practice I can learn from.
Thanks.
K. Frank
_______________________________________________
Interest mailing list
http://lists.qt-project.org/mailman/listinfo/interest
André Somers
2013-02-19 13:38:18 UTC
Permalink
Post by K. Frank
Hello List!
Sometimes I have a simple class, maybe a POD, that I want to
pump through a queued signal-slot connection. As I understand
it, I need a QObject to do that. So I wrap my class in QObject.
No, you don't. In fact, it is a Bad Idea(TM).
In order to send your POD as a signal/slot argument, it needs to be
copyable. However, QObject is explicitly *not* copyable.

As Samual already said: use Q_DECLARE_METATYPE instead.

André
Post by K. Frank
What are some good idioms for this? What is the most parsimonious
approach?
#include "pod.h"
#include <QObject>
#include <QMetaType>
class WrappedPOD : public QObject, public POD {
Q_OBJECT
WrappedPOD() {}
WrappedPOD (const WrappedPOD &wp) : POD(wp) {}
WrappedPOD (const POD &p) : POD(p) {}
~WrappedPOD() {}
};
(A comment: I was a little surprised that I seem to need to define
the constructors. I would have thought that the c++ defaults would
have sufficed.)
Any thoughts on other, better ways to achieve this goal? Or is there
an approach I can use that avoids wrapping the object in the first place?
I imagine that this is not an uncommon need, so I imagine that there
is some standard practice I can learn from.
Thanks.
K. Frank
_______________________________________________
Interest mailing list
http://lists.qt-project.org/mailman/listinfo/interest
Tony Rietwyk
2013-02-19 23:13:27 UTC
Permalink
Hi Frank,
Sent: Wednesday, 20 February 2013 12:19 AM
Hello List!
Sometimes I have a simple class, maybe a POD, that I want to pump through
a queued signal-slot connection. As I understand it, I need a QObject to
do
that. So I wrap my class in QObject.
You can pass pointers to the POD without doing anything else:

signals:
void my_signal(POD *data);

If it really must be POD by value, then use Samuel's approach.

Tony.
K. Frank
2013-02-20 02:47:08 UTC
Permalink
Hi Tony!
Post by Tony Rietwyk
Hi Frank,
Sent: Wednesday, 20 February 2013 12:19 AM
Hello List!
Sometimes I have a simple class, maybe a POD, that I want to pump through
a queued signal-slot connection. As I understand it, I need a QObject to
do
that. So I wrap my class in QObject.
void my_signal(POD *data);
Thanks for noting that.

It seems a little odd, though. I could of sworn I tried passing a reference:

void my_signal (const POD &data)

and it failed at run time when I tried to pass the reference through a
queued connection.

Of course, pointers and references are not identical, but, under the
hood, you would think that if a queued connection could handle one,
it could handle the other.

Is it in fact the case that queued connections can handle pointers
but not references (to non-qmetatypes), or am I just misremembering
what I did?
Post by Tony Rietwyk
If it really must be POD by value, then use Samuel's approach.
Well, in my case it certainly doesn't have to be by value, but by
value or by reference stylistically reflects the by-value semantics
of the POD.
Post by Tony Rietwyk
Tony.
Thanks.


K. Frank
Thiago Macieira
2013-02-20 03:36:14 UTC
Permalink
Post by K. Frank
Thanks for noting that.
void my_signal (const POD &data)
and it failed at run time when I tried to pass the reference through a
queued connection.
I've seen some people report this problem if they forgot to #include the full
declaration of the type. I really don't know how anything even compiled, but
it seems to cause the problem.
Post by K. Frank
Of course, pointers and references are not identical, but, under the
hood, you would think that if a queued connection could handle one,
it could handle the other.
Quite to the contrary! Const-references and pointers are *very* different.
Const-references are identical to passing by value as far as the signal-slot
connection mechanism is concerned. When you write:

void my_signal(const POD &data);

you may see that the meta object registers a signal "my_signal(POD)".
Therefore, the metatype system will try to call POD's copy constructor which
was registered with qRegisterMetaType.

If you pass a pointer, then it simply copies the pointer. It's your
responsibility to ensure that the pointer remains valid at the indeterminate
time later when the slot is called in the other thread.

And finally, non-const references cannot be used in a queued connection.
Post by K. Frank
Is it in fact the case that queued connections can handle pointers
but not references (to non-qmetatypes), or am I just misremembering
what I did?
You were remembering correctly.
Post by K. Frank
Post by Tony Rietwyk
If it really must be POD by value, then use Samuel's approach.
Well, in my case it certainly doesn't have to be by value, but by
value or by reference stylistically reflects the by-value semantics
of the POD.
--
Thiago Macieira - thiago.macieira (AT) intel.com
Software Architect - Intel Open Source Technology Center
Loading...