我没有严格遵循Qt中的doc。而不是使用新的我使用静态局部变量来能够调用单例类的析构函数。差异在here中描述。
我的问题是退出我的程序时,我的一个单例类导致它崩溃。在调试模式下,调试器将停止在该类的析构函数中。这个单例类和其他类之间的不同之处在于我的QML和cpp文件都使用了这个。
我的问题是我是否必须使用new关键字为此单例分配实例?
头
class AppConfiguration : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(AppConfiguration)
Q_PROPERTY(bool serverMode READ serverMode WRITE setServerMode NOTIFY serverModeChanged)
public:
static QObject* instance(QQmlEngine* engine = NULL, QJSEngine* scriptEngine = NULL);
~AppConfiguration();
protected:
AppConfiguration();
private:
static QObject* s_instance;
};
CPP
QObject* AppConfiguration::s_instance = NULL;
QObject* AppConfiguration::instance(QQmlEngine *engine,
QJSEngine *scriptEngine)
{
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
static AppConfiguration s_instance;
return &s_instance;
}
AppConfiguration::AppConfiguration() :
m_serverMode(true)
{
}
AppConfiguration::~AppConfiguration()
{
}
主
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
qmlRegisterSingletonType<AppConfiguration>("com.synergy.gui", 1, 0, "AppConfiguration", &AppConfiguration::instance);
QQmlApplicationEngine engine(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
QML
Switch {
id: modeSwitch
x: 4
y: 31
transformOrigin: Item.Center
checked: AppConfiguration.serverMode
Binding {
target: AppConfiguration
property: "serverMode"
value: modeSwitch.checked
}
Connections {
target: AppConfiguration
onServerModeChanged: {
modeSwitch.checked = AppConfiguration.serverMode
}
}
}
答案 0 :(得分:6)
你自己回答了这个问题:
我没有严格遵循Qt中的文档。而不是使用新的我使用静态局部变量来调用单例类的析构函数。
这是不允许的。文档告诉你:
注意:从单例类型返回的QObject单例类型实例 提供商归QML引擎所有。出于这个原因,单身人士 类型提供程序函数不应该实现为单例 工厂。
Qml以每种QQmlEngine
的方式工作,AppConfiguration::instance
函数将被调用。 QML-singeltons是每个引擎的单位数,而不是每个应用程序。因此,一旦引擎被破坏,Qt将自动销毁实例。
你得到一个错误,因为这样同一个对象被破坏两次,一旦QML引擎被破坏,最后,在关闭时,静态段被清除。多数民众赞成在崩溃。
要解决此问题,您需要为QQmlEngine
设置一个实例,即使用new
创建实例。没有其他办法。要获得全局singelton,请尝试创建2个类:
修改强>
要通过2个类实现它,您可以创建以下代码:
第一类(真正的单身人士)基本保持不变:
appconfiguration.h
class AppConfiguration : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(AppConfiguration)
Q_PROPERTY(bool serverMode READ serverMode WRITE setServerMode NOTIFY serverModeChanged)
public:
static AppConfiguration* instance();
~AppConfiguration();
protected:
AppConfiguration();
private:
static AppConfiguration s_instance;//is static -> destructor will be called
};
appconfiguration.cpp
AppConfiguration AppConfiguration::s_instance;
AppConfiguration* AppConfiguration::instance()
{
return &AppConfiguration::s_instance;//just return the static instance here
}
//...
现在是第二节课。由于它需要具有QML属性,因此您必须创建新的标头和源。例如,您可以将其命名为QmlAppConfiguration
:
qmlappconfiguration.h
class QmlAppConfiguration : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(QmlAppConfiguration)
//forward all properties/signals/slots...
Q_PROPERTY(bool serverMode READ serverMode WRITE setServerMode NOTIFY serverModeChanged)
public:
static QObject* instance(QQmlEngine* engine = NULL, QJSEngine* scriptEngine = NULL);
bool serverMode() const;
public slots:
void setServerMode(bool serverMode);
signals:
void serverModeChanged(bool serverMode);
private:
QmlAppConfiguration();
}
qmlappconfiguration.cpp
QObject* QmlAppConfiguration::instance(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
return new QmlAppConfiguration();// a new instance for each engine
}
bool QmlAppConfiguration::serverMode() const
{
return AppConfiguration::instance()->serverMode();//forwarded
}
void QmlAppConfiguration::setServerMode(bool serverMode) const
{
AppConfiguration::instance()->setServerMode(serverMode);//forwarded
}
QmlAppConfiguration::QmlAppConfiguration()
{
//to make shure signals get forwared, connect them here
//and yes, you can connect signals to signals
connect(AppConfiguration::instance(), &AppConfiguration::serverModeChanged,
this, &QmlAppConfiguration::serverModeChanged);
}
最后但并非最不重要的是,修改您的主要内容。如果您按照下面所述的方式进行操作,则无需修改QML文件:
int main(int argc, char **argv)
{
//...
qmlRegisterSingletonType<QmlAppConfiguration>("com.synergy.gui", 1, 0, "AppConfiguration", &QmlAppConfiguration::instance);
//...
}
就是这样!现在你有1个真正的单例类,AppConfiguration
,可以在c ++中使用。由于它是一个静态实例,因此将在退出时调用析构函数。在QML中,您现在拥有一个名为AppConfiguration
的类,但在内部使用QmlAppConfiguration
的(多个)实例,这些实例只是真正的单例类的“委托”。我希望这会有所帮助。
答案 1 :(得分:5)
在 AppConfiguration :: instance 功能中,您只需添加一行:
QQmlEngine::setObjectOwnership(&s_instance, QQmlEngine::CppOwnership);
所以全功能定义如下:
QObject* AppConfiguration::instance(QQmlEngine *engine,
QJSEngine *scriptEngine) {
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
static AppConfiguration s_instance;
QQmlEngine::setObjectOwnership(&s_instance, QQmlEngine::CppOwnership);
return &s_instance;
}