如何使用 Q_GLOBAL_STATIC 插件?
How to use Q_GLOBAL_STATIC with plugins?
如何通过插件使用Q_GLOBAL_STATIC?
我想全部使用 "global" QMap,这样我就不必在不同的地方保存 QMap 并每次都同步它。
正如我所读,Q_GLOBAL_STATIC 应该可以完成这项工作。
我的 Qt 项目具有以下结构:
.
+-- common
| +-- common.pro
| +-- singleton.h
| +-- singleton.cpp [contains Q_GLOBAL_STATIC and returns it via instance() static method]
+-- plugins
| +-- p1
| | +-- p1.pro
| | +-- ...
| +-- p2
| | +-- p2.pro
| | +-- ...
| +-- plugins.pro [TEMPLATE = subdirs]
+-- app
| +-- app.pro
| +-- app.cpp
| +-- ...
+-- project.pro [TEMPLATE = subdirs]
main函数(在app.cpp中)是第一个调用单例的地方。
因此它是在加载插件之前创建并已知的。
目前我正在考虑将 singleton.o 和 link 生成的目标文件编译为应用程序和插件。
但是如何只编译目标文件呢?
也许我必须将 TEMPLATE(在 common.pro 中)指定为 lib?
如果是这样,它应该是共享库还是静态库?
共享库没有代码副本,所以也许这对单例来说是必需的,对吧?
我的想法是否正确,我是否可以在不显式共享指针的情况下拥有一个单例,仅通过使用 Q_GLOBAL_STATIC?
可以共享全局静态实例,只是不是以您期望的方式。
首先,Q_GLOBAL_STATIC 只是一个宏,用于创建具有线程安全性的某个 class 的 local 实例。所以这基本上是一种奇特的方式:
static MyCass *instance() {
static auto _instance = new MyClass();
return _instance;
}
#define myGlobalStatic instance()
宏的优点是,您可以节省代码,它是惰性的,并且它具有线程安全的构造函数和析构函数。换句话说,使用此宏创建一个本地实例 使 可以在全局范围内安全地使用它。
这意味着即使您在不同的源文件中有相同的 Q_GLOBAL_STATIC 语句,也会有多个不同的实例,所有实例都命名相同,但仅在本地可用。
这也适用于您的具体想法:在 singleton.o 中将有一个这样的实例 - 但是,通过 link 将其转换为 3 个不同的二进制文件(app、p1、p2),您基本上创建 3 个不同的实例,每个二进制文件都是本地的(因为 linker 将它从目标文件复制到每个二进制文件中)!所以不,你现在的想法不会共享实例。
存档的唯一方法是创建一个 动态 linked 库,其中包含单个实例和 export来自它的 getter 函数提供对实例的访问。 Link 针对这个库的两个插件和应用程序,在运行时,只有 1 个实例(作为库的一部分),所有 3 个都可以访问。
对于您的项目,这意味着您必须将 common 变成一个共享库,并且 link app、p1 和 p2 反对它。
然而,还有第二种方法可以做到这一点,独立于 Q_GLOBAL_STATIC。这个想法的唯一要求是,无论您在全球范围内共享什么,都在应用程序以外的其他地方定义。使用 QMap
会起作用,因为它是 Qt5Core 库的一部分。
我们的想法是不使用应用程序和插件可以访问的全局实例,而是向插件接口添加一个设置方法,将实例传递给插件:
class MyPlugin
{
Q_DISABLE_COPY(MyPlugin)
public:
MyPlugin() = default;
virtual ~MyPlugin() = default;
// This is the important part: have a setup method
virtual void setup(QMap<QString, int> &globalMap) = 0;
};
现在,您只需在每次从您的应用实例化一个新插件时调用 setup
即可,一切顺利!您可以简单地在加载插件的源文件中包含 Q_GLOBAL_STATIC,或者甚至让它成为某个顶级 class.
的成员
现在它可以使用 qApp 对实例方法进行一些修改。
/* [singleton.h] */
class Singleton : public QObject {
/* ... */
};
Q_DECLARE_OPAQUE_POINTER(Singleton *)
Q_DECLARE_METATYPE(Singleton *)
/* [singleton.cpp] */
Singleton * Singleton::instance() {
static Singleton * __ptr(NULL);
if (!qApp->property("singletonkey").isValid() && !__ptr) {
__ptr = ptr_from_macro; // Q_GLOBAL_STATIC pointer
qApp->setProperty("singletonkey", QVariant::fromValue(__ptr));
} else if (!__ptr) {
__ptr = qvariant_cast<Singleton *>(qApp->property("singletonkey"));
} else if (!qApp->property("singletonkey").isValid()) {
qApp->setProperty("singletonkey", QVariant::fromValue(__ptr));
}
return __ptr;
}
希望这不会导致其他问题🙈
如何通过插件使用Q_GLOBAL_STATIC? 我想全部使用 "global" QMap,这样我就不必在不同的地方保存 QMap 并每次都同步它。 正如我所读,Q_GLOBAL_STATIC 应该可以完成这项工作。
我的 Qt 项目具有以下结构:
.
+-- common
| +-- common.pro
| +-- singleton.h
| +-- singleton.cpp [contains Q_GLOBAL_STATIC and returns it via instance() static method]
+-- plugins
| +-- p1
| | +-- p1.pro
| | +-- ...
| +-- p2
| | +-- p2.pro
| | +-- ...
| +-- plugins.pro [TEMPLATE = subdirs]
+-- app
| +-- app.pro
| +-- app.cpp
| +-- ...
+-- project.pro [TEMPLATE = subdirs]
main函数(在app.cpp中)是第一个调用单例的地方。 因此它是在加载插件之前创建并已知的。
目前我正在考虑将 singleton.o 和 link 生成的目标文件编译为应用程序和插件。 但是如何只编译目标文件呢?
也许我必须将 TEMPLATE(在 common.pro 中)指定为 lib? 如果是这样,它应该是共享库还是静态库? 共享库没有代码副本,所以也许这对单例来说是必需的,对吧?
我的想法是否正确,我是否可以在不显式共享指针的情况下拥有一个单例,仅通过使用 Q_GLOBAL_STATIC?
可以共享全局静态实例,只是不是以您期望的方式。
首先,Q_GLOBAL_STATIC 只是一个宏,用于创建具有线程安全性的某个 class 的 local 实例。所以这基本上是一种奇特的方式:
static MyCass *instance() {
static auto _instance = new MyClass();
return _instance;
}
#define myGlobalStatic instance()
宏的优点是,您可以节省代码,它是惰性的,并且它具有线程安全的构造函数和析构函数。换句话说,使用此宏创建一个本地实例 使 可以在全局范围内安全地使用它。
这意味着即使您在不同的源文件中有相同的 Q_GLOBAL_STATIC 语句,也会有多个不同的实例,所有实例都命名相同,但仅在本地可用。
这也适用于您的具体想法:在 singleton.o 中将有一个这样的实例 - 但是,通过 link 将其转换为 3 个不同的二进制文件(app、p1、p2),您基本上创建 3 个不同的实例,每个二进制文件都是本地的(因为 linker 将它从目标文件复制到每个二进制文件中)!所以不,你现在的想法不会共享实例。
存档的唯一方法是创建一个 动态 linked 库,其中包含单个实例和 export来自它的 getter 函数提供对实例的访问。 Link 针对这个库的两个插件和应用程序,在运行时,只有 1 个实例(作为库的一部分),所有 3 个都可以访问。
对于您的项目,这意味着您必须将 common 变成一个共享库,并且 link app、p1 和 p2 反对它。
然而,还有第二种方法可以做到这一点,独立于 Q_GLOBAL_STATIC。这个想法的唯一要求是,无论您在全球范围内共享什么,都在应用程序以外的其他地方定义。使用 QMap
会起作用,因为它是 Qt5Core 库的一部分。
我们的想法是不使用应用程序和插件可以访问的全局实例,而是向插件接口添加一个设置方法,将实例传递给插件:
class MyPlugin
{
Q_DISABLE_COPY(MyPlugin)
public:
MyPlugin() = default;
virtual ~MyPlugin() = default;
// This is the important part: have a setup method
virtual void setup(QMap<QString, int> &globalMap) = 0;
};
现在,您只需在每次从您的应用实例化一个新插件时调用 setup
即可,一切顺利!您可以简单地在加载插件的源文件中包含 Q_GLOBAL_STATIC,或者甚至让它成为某个顶级 class.
现在它可以使用 qApp 对实例方法进行一些修改。
/* [singleton.h] */
class Singleton : public QObject {
/* ... */
};
Q_DECLARE_OPAQUE_POINTER(Singleton *)
Q_DECLARE_METATYPE(Singleton *)
/* [singleton.cpp] */
Singleton * Singleton::instance() {
static Singleton * __ptr(NULL);
if (!qApp->property("singletonkey").isValid() && !__ptr) {
__ptr = ptr_from_macro; // Q_GLOBAL_STATIC pointer
qApp->setProperty("singletonkey", QVariant::fromValue(__ptr));
} else if (!__ptr) {
__ptr = qvariant_cast<Singleton *>(qApp->property("singletonkey"));
} else if (!qApp->property("singletonkey").isValid()) {
qApp->setProperty("singletonkey", QVariant::fromValue(__ptr));
}
return __ptr;
}
希望这不会导致其他问题🙈