Move-enable QSignalBlocker

When QSignalBlocker was reviewed, move semantics were asked for.
This patch add them.

This makes QSignalBlocker usable as a by-value argument (to transfer
control of signal blocking into a function) as well as as a return
value (to transfer control of signal blocking out of a function).

Change-Id: I714aa2a283bb33dba76e860649e88ed202e913c5
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
This commit is contained in:
Marc Mutz 2013-11-17 16:13:08 +01:00 committed by The Qt Project
parent 5e519b31dc
commit 4031cb8610
3 changed files with 153 additions and 1 deletions

View File

@ -529,6 +529,27 @@ void QMetaCallEvent::placeMetaCall(QObject *object)
Calls \a{object}.blockSignals(true).
*/
/*!
\fn QSignalBlocker::QSignalBlocker(QSignalBlocker &&other)
Move-constructs a signal blocker from \a other. \a other will have
a no-op destructor, while repsonsibility for restoring the
QObject::signalsBlocked() state is transferred to the new object.
*/
/*!
\fn QSignalBlocker &QSignalBlocker::operator=(QSignalBlocker &&other)
Move-assigns this signal blocker from \a other. \a other will have
a no-op destructor, while repsonsibility for restoring the
QObject::signalsBlocked() state is transferred to this object.
The object's signals this signal blocker was blocking prior to
being moved to, if any, are unblocked \em except in the case where
both instances block the same object's signals and \c *this is
unblocked while \a other is not, at the time of the move.
*/
/*!
\fn QSignalBlocker::~QSignalBlocker()

View File

@ -556,11 +556,16 @@ public:
inline explicit QSignalBlocker(QObject &o);
inline ~QSignalBlocker();
#ifdef Q_COMPILER_RVALUE_REFS
inline QSignalBlocker(QSignalBlocker &&other);
inline QSignalBlocker &operator=(QSignalBlocker &&other);
#endif
inline void reblock();
inline void unblock();
private:
Q_DISABLE_COPY(QSignalBlocker)
QObject * const m_o;
QObject * m_o;
bool m_blocked;
bool m_inhibited;
};
@ -577,6 +582,32 @@ QSignalBlocker::QSignalBlocker(QObject &o)
m_inhibited(false)
{}
#ifdef Q_COMPILER_RVALUE_REFS
QSignalBlocker::QSignalBlocker(QSignalBlocker &&other)
: m_o(other.m_o),
m_blocked(other.m_blocked),
m_inhibited(other.m_inhibited)
{
other.m_o = 0;
}
QSignalBlocker &QSignalBlocker::operator=(QSignalBlocker &&other)
{
if (this != &other) {
// if both *this and other block the same object's signals:
// unblock *this iff our dtor would unblock, but other's wouldn't
if (m_o != other.m_o || (!m_inhibited && other.m_inhibited))
unblock();
m_o = other.m_o;
m_blocked = other.m_blocked;
m_inhibited = other.m_inhibited;
// disable other:
other.m_o = 0;
}
return *this;
}
#endif
QSignalBlocker::~QSignalBlocker()
{
if (m_o && !m_inhibited)

View File

@ -103,6 +103,7 @@ private slots:
void recursiveSignalEmission();
#endif
void signalBlocking();
void signalBlockingMoveAssignment();
void blockingQueuedConnection();
void childEvents();
void installEventFilter();
@ -3030,6 +3031,105 @@ void tst_QObject::signalBlocking()
receiver.reset();
}
void tst_QObject::signalBlockingMoveAssignment()
{
#ifdef Q_COMPILER_RVALUE_REFS
QObject o1, o2;
// move-assignment: both block other objects
{
QSignalBlocker b(&o1);
QVERIFY(o1.signalsBlocked());
QVERIFY(!o2.signalsBlocked());
b = QSignalBlocker(&o2);
QVERIFY(!o1.signalsBlocked());
QVERIFY(o2.signalsBlocked());
}
QVERIFY(!o1.signalsBlocked());
QVERIFY(!o2.signalsBlocked());
// move-assignment: from inert other
{
QSignalBlocker b(&o1);
QVERIFY(o1.signalsBlocked());
b = QSignalBlocker(0);
}
QVERIFY(!o1.signalsBlocked());
QVERIFY(!o2.signalsBlocked());
// move-assignment: to inert *this
{
QSignalBlocker b(0);
QVERIFY(!o1.signalsBlocked());
{
QSignalBlocker inner(&o1);
QVERIFY(o1.signalsBlocked());
b = std::move(inner);
}
QVERIFY(o1.signalsBlocked());
}
QVERIFY(!o1.signalsBlocked());
QVERIFY(!o2.signalsBlocked());
// move-assignment: both block the same object, neither is unblocked
{
QSignalBlocker b(&o1);
QVERIFY(o1.signalsBlocked());
{
b.unblock(); // make sure inner.m_blocked = false
QVERIFY(!o1.signalsBlocked());
QSignalBlocker inner(&o1);
QVERIFY(o1.signalsBlocked());
b.reblock();
QVERIFY(o1.signalsBlocked());
b = std::move(inner);
}
QVERIFY(o1.signalsBlocked());
}
QVERIFY(!o1.signalsBlocked());
QVERIFY(!o2.signalsBlocked());
// move-assignment: both block the same object, but *this is unblocked
{
QSignalBlocker b(&o1);
QVERIFY(o1.signalsBlocked());
b.unblock();
QVERIFY(!o1.signalsBlocked());
b = QSignalBlocker(&o1);
QVERIFY(o1.signalsBlocked());
}
QVERIFY(!o1.signalsBlocked());
QVERIFY(!o2.signalsBlocked());
// move-assignment: both block the same object, but other is unblocked
{
QSignalBlocker b(&o1);
{
QVERIFY(o1.signalsBlocked());
QSignalBlocker inner(&o1);
QVERIFY(o1.signalsBlocked());
inner.unblock();
QVERIFY(o1.signalsBlocked());
b = std::move(inner);
QVERIFY(!o1.signalsBlocked());
}
QVERIFY(!o1.signalsBlocked());
}
QVERIFY(!o1.signalsBlocked());
QVERIFY(!o2.signalsBlocked());
#else
QSKIP("This compiler is not in C++11 mode or doesn't support move semantics");
#endif // Q_COMPILER_RVALUE_REFS
}
void tst_QObject::blockingQueuedConnection()
{
{