From 842cfcec80f9ddb20e6530e2dbbc71df68e96a94 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Sat, 24 Jun 2023 12:39:43 +0200 Subject: [PATCH] QObject: introduce QT_NO_CONTEXTLESS_CONNECT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 3-arguments overload of connect() is error-prone / easy to misuse: * it's easy to e.g. connect to a lambda, and capture local state in the lambda. By not passing a receiver/context, the connection won't get disconnected if the local state gets destroyed (effectively, it creates a "dangling connection"); * in a multithread scenario, one may not realize that the connection is forced to be direct. If the signal is emitted in another thread than the one establishing the connection¹, then the functor will be invoked in that other thread. (Not that "the thread establishing the connection" has ever mattered, but again, this API is error-prone.) Add a macro that allows users to disable the overload in their project. I'm not going for deprecation because there's simply too much code around that uses it. [ChangeLog][QtCore][QObject] Added the QT_NO_CONTEXTLESS_CONNECT macro. Defining the macro before including any Qt header will disable the overload of QObject::connect that does not take a receiver/context argument. Change-Id: I86af1029c1a211ea365f417aae9038d3fcacadfd Reviewed-by: Thiago Macieira --- src/corelib/kernel/qobject.cpp | 27 +++++++++++++++++++++++++++ src/corelib/kernel/qobject.h | 2 ++ 2 files changed, 29 insertions(+) diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 4304add49c..e2c73d58ab 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -4854,6 +4854,28 @@ QDebug operator<<(QDebug dbg, const QObject *o) \sa QObject::connect */ +/*! + \macro QT_NO_CONTEXTLESS_CONNECT + \relates QObject + \since 6.7 + + Defining this macro will the overload of QObject::connect() that + connects a signal to a functor, without also specifying a QObject + as a receiver/context object (that is, the 3-arguments overload + of QObject::connect()). + + Using the context-less overload is error prone, because it is easy + to connect to functors that depend on some local state of the + receiving end. If such local state gets destroyed, the connection + does not get automatically disconnected. + + Moreover, such connections are always direct connections, which may + cause issues in multithreaded scenarios (for instance, if the + signal is emitted from another thread). + + \sa QObject::connect, Qt::ConnectionType +*/ + /*! \typedef QObjectList \relates QObject @@ -4959,6 +4981,11 @@ void qDeleteInEventHandler(QObject *o) However, you should take care that any objects used within the functor are still alive when the signal is emitted. + For this reason, it is recommended to use the overload of connect() + that also takes a QObject as a receiver/context. It is possible + to disable the usage of the context-less overload by defining the + \c{QT_NO_CONTEXTLESS_CONNECT} macro. + Overloaded functions can be resolved with help of \l qOverload. */ diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index 182edaf7f2..3d1c102fc5 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -235,6 +235,7 @@ public: type, types, &SignalType::Object::staticMetaObject); } +#ifndef QT_NO_CONTEXTLESS_CONNECT //connect without context template static inline QMetaObject::Connection @@ -242,6 +243,7 @@ public: { return connect(sender, signal, sender, std::forward(slot), Qt::DirectConnection); } +#endif // QT_NO_CONTEXTLESS_CONNECT #endif //Q_QDOC static bool disconnect(const QObject *sender, const char *signal,