Discussion:
[Interest] QMetaMethod::invoke / Q_ARG with a temporary
Christian Ehrlicher
2018-05-07 18:24:55 UTC
Permalink
Hi,

today I discovered that Q_QArgument does not handle a temporary
(boolean) value as I would have expected it.
I'm invoking the method similar to this:

QArgument<bool> arg3("bool", !inProgress);
request.replySlot.invoke(m_objToInform, Qt::QueuedConnection, arg1,
arg2, arg3);

Changing it to
bool bFinished = !inProgress;
QArgument<bool> arg3("bool", bFinished);
fixes the problem but I'm not sure if the compiler can maybe optimize it
away...

I did not found a hint int the documentation about this behavior.
Therefore my question - should this work for a queued connection or not?
At least msvc2017 and gcc 4.8 don't like it when compiling with -O2...

Thx,
Christian
Richard Weickelt
2018-05-07 20:06:35 UTC
Permalink
today I discovered that Q_QArgument does not handle a temporary (boolean)
value as I would have expected it.
QArgument<bool> arg3("bool", !inProgress);
request.replySlot.invoke(m_objToInform, Qt::QueuedConnection, arg1, arg2,
arg3);
I think your expectation is wrong. QArgument does not store the value, but
the value's location. The lifetime of !inProgress does not exceed
QArgument's constructor and hence, !inProgress does not exist anymore after
above line.

If it works for direct connections, then this is only luck because the
temporary variable !inProgress might still exist.
Changing it to
bool bFinished = !inProgress;
QArgument<bool> arg3("bool", bFinished);
fixes the problem but I'm not sure if the compiler can maybe optimize it
away...> I did not found a hint int the documentation about this behavior. Therefore
my question - should this work for a queued connection or not? At least
msvc2017 and gcc 4.8 don't like it when compiling with -O2...
I haven't looked at the implementation of asynchronous signals and slots,
but I would guess that Qt caches only the QArgument object (the one that
contains the pointer to the data). Thus, the variable bFinished must exist
physically in the moment when the slot is invoked. I think you need to move
your variable to the heap if the slot is invoked after the current stack
context is left.

Richard
Thiago Macieira
2018-05-07 19:40:00 UTC
Permalink
Post by Christian Ehrlicher
Hi,
today I discovered that Q_QArgument does not handle a temporary
(boolean) value as I would have expected it.
QArgument<bool> arg3("bool", !inProgress);
QArgument is not a documented class. Remove this line. You must only use the
Q_ARG macro.
Post by Christian Ehrlicher
I did not found a hint int the documentation about this behavior.
Now you know why.
--
Thiago Macieira - thiago.macieira (AT) intel.com
Software Architect - Intel Open Source Technology Center
Giuseppe D'Angelo
2018-05-07 20:12:14 UTC
Permalink
Post by Christian Ehrlicher
I did not found a hint int the documentation about this behavior.
Therefore my question - should this work for a queued connection or not?
At least msvc2017 and gcc 4.8 don't like it when compiling with -O2...
The documentation doesn't talk about QArgument, but about Q_ARG and
Q_RETURN_ARG, which is what you should use.

(Under the hood, the problem is that QArgument simply stores a pointer
to your variable. If that variable is a temporary, that pointer becomes
immediately dangling. For this reason, do not store what Q_ARG builds,
e.g. in an variable declared auto!)

HTH,
--
Giuseppe D'Angelo | ***@kdab.com | Senior Software Engineer
KDAB (France) S.A.S., a KDAB Group company
Tel. France +33 (0)4 90 84 08 53, http://www.kdab.com
KDAB - The Qt, C++ and OpenGL Experts
Sze Howe Koh
2018-05-09 10:27:14 UTC
Permalink
Post by Giuseppe D'Angelo
Post by Christian Ehrlicher
I did not found a hint int the documentation about this behavior.
Therefore my question - should this work for a queued connection or not?
At least msvc2017 and gcc 4.8 don't like it when compiling with -O2...
The documentation doesn't talk about QArgument, but about Q_ARG and
Q_RETURN_ARG, which is what you should use.
(Under the hood, the problem is that QArgument simply stores a pointer to
your variable. If that variable is a temporary, that pointer becomes
immediately dangling. For this reason, do not store what Q_ARG builds, e.g.
in an variable declared auto!)
From Qt 5.10 onwards, we can even do without Q_ARG (and QArgument).
Pass a function pointer or lambda expression to
QMetaObject::invokeMethod().


Regards,
Sze-Howe

Loading...