I'd like to know what are the implications (problems) of having multiple QApplication
/QCoreApplication
instances in the same process, and how to solve some issues regarding it.
The scenario is as follows: I'd like to make a wrapper on a open source third-party application in order to convert it into an embeddable widget as an optional plugin (the application consists basically on a single QMainWindow
-based interface).
Such project heavily relies on a QCoreApplication
derived class but basically because it is used as an already existing singleton. I'm able to modify the code (and I'll have to do so in order to expose the QMainWindow
as an embeddable widget), although for the complexity of that project I cannot simply remove the parent class.
So, the final application will have its own QApplication
(created on start) and then will optionally load the aforementioned plugin (thus creating the second QCoreApplication
). Only the first (main) QApplication
is used for events loop (QCoreApplication::exec()
).
I'm aware of the facts that QCoreApplication
is a singleton. In my tests, the singleton always points to the last created instance:
qDebug() << qApp;
auto app1 = new QApplication(argc, argv);
qDebug() << qApp;
auto app2 = new TheOtherQApplication(argc, argv);
qDebug() << qApp;
The output is
QObject(0x0)
QApplication(0x6f9400, name = "test")
ASSERT failure in QCoreApplication: "there should be only one application object", file kernel\qcoreapplication.cpp, line 595
TheOtherQApplication(0x2550dc0, name = "test")
TheOtherQApplication(0x2550dc0, name = "test") TheOtherQApplication(0x2550dc0, name = "test")
As it can be seen, after the second QApplication
is created it replaces the global instance. Is there any way to solve this? As the plugin is optional the obvious answer (loading the main QApplication
on second place) is not a suitable option.
Also, are there any other implications of having multiple QApplication
instances? Or are all related to the events loop (checked) and the singleton?
Note: This is a project based on Qt 4.7 due to third-party dependencies not fully updated yet. It is planned to be migrated to the latest version in a year or so, but for the moment I have to deal with 4.7.
BTW, I've already reviewed several related questions, including this one but that doesn't provide any useful information.
Well, as far as I've been able to understand, using two or more Q*Application
s (QCoreApplication
, QGuiApplication
, QApplication
) implies:
An assert fails in debug mode when creating the second application (or more). No crashes in release mode.
Each instantiation of Q*Application
updates the singleton (i.e., qApp
will always point to the last instance).
Global attributes such as application name and version are transferred along instances and override former ones.
Any signal connected to a slot of a Q*Application
calls the slot of the singleton, even if connected before creating the newest instances.
Only slots connected to signals of latest Q*Application
will be called (they are not transferred to the new instance).
Translators are not transferred when new Q*Application
instances are created.
If the last Q*Application
is destroyed then the singleton becomes null (it does not fallback to the previous instance).
You can test these features using the following code and toggling USE_TWO_QAPPS
:
#include <QtCore>
#define USE_TWO_QAPPS
int main(int argc, char* argv[])
{
QTranslator tr1;
QCoreApplication a1(argc, argv);
a1.setApplicationName("a1");
a1.installTranslator(&tr1);
qDebug() << qApp << &a1;
qDebug() << "a1.applicationName() =" << a1.applicationName();
// qApp == &a1
QObject::connect(&a1, &QCoreApplication::aboutToQuit, []() {
// point 5, never called with Q*Application
qDebug() << "Hello world from a1!";
});
QTimer::singleShot(2000, &a1, &QCoreApplication::quit); // as if connected to latest qApp, point 4
#ifdef USE_TWO_QAPPS
// if (true) { // uncomment to test point 7
QCoreApplication a2(argc, argv);
a2.setApplicationName("a2");
qDebug() << qApp << &a1 << &a2; // test point 2
qDebug() << "a2.applicationName() =" << a2.applicationName();
qDebug() << "a1.applicationName() =" << a1.applicationName(); // as if called from qApp, point 3
QObject::connect(&a2, &QCoreApplication::aboutToQuit, []() {
qDebug() << "Hello world from a2!";
});
// } // uncomment to test point 7
#endif
qDebug() << qApp->removeTranslator(&tr1); // false if the translator is not installed, point 6
a1.installTranslator(&tr1); // it is installed in the latest instance (as if called from qApp)
qDebug() << qApp->removeTranslator(&tr1);
return qApp->exec();
}
Results with one Q*Application
QCoreApplication(0xfafb74) QCoreApplication(0xfafb74)
a1.applicationName() = "a1"
true
true
Hello world from a1!
Results with two Q*Application
QCoreApplication(0xbefb2c) QCoreApplication(0xbefb2c)
a1.applicationName() = "a1"
ASSERT failure in QCoreApplication: "there should be only one application object", file ########\qtbase\src\corelib\kernel\qcoreapplication.cpp, line 769
QCoreApplication(0xbefb1c) QCoreApplication(0xbefb2c) QCoreApplication(0xbefb1c)
a2.applicationName() = "a2"
a1.applicationName() = "a2"
false
true
Hello world from a2!
When testing point 7, a2
is destroyed when quitting the if
statement. In this case, every call to Q*Application
methods done raises a warning and are not executed (they don't crash and no asserts are broken). It happens even when calling from the previous application: a1.installTranslator(&tr1);
QApplication::installTranslator: Please instantiate the QApplication object first
Note: tested using Visual Studio 2010. Qt versions are 4.7 and 5.6.1-1, both with identical results
UPDATE: a cleaner code version for this answer is available in https://github.com/cbuchart/stackoverflow/blob/master/46304070-multiple-qapplication-instances/main.cpp
Following comments, this code also tests what happens when all QApplication
objects are destroyed and then created again. Results: as expected nothing special occurs, no side effects seems to be present.
Conclusion
It seems possible to work with two or more Q*Application
having in mind these points, being the more critical the fact that, when done on any but last Q*Application
, connections to signals are lost and translators are not installed. Also, if the last instance is destroyed then no application is available, so you should take care of those cases (for example, if unloading a DLL that created the last instance).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With