Как использовать Q_GLOBAL_STATIC с плагинами? - PullRequest
0 голосов
/ 31 января 2019

Как использовать Q_GLOBAL_STATIC с плагинами?Я хочу использовать «глобальный» 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]

Основная функция (в app.cpp) - это первое место, вызывающеесинглтон.Итак, он создан и известен до загрузки плагина.

В настоящее время я думаю скомпилировать singleton.o и связать полученный объектный файл с приложением и плагинами.Но как скомпилировать только объектный файл?

Может быть, мне нужно указать ШАБЛОН (в common.pro) как lib?Если это так, должна ли это быть общая или статическая библиотека?Shared lib не имеет копии кода, так что, может быть, это нужно для синглтона над всеми, верно?

Правильно ли я думаю и могу ли я иметь синглтон над всеми без явного совместного использования указателя, только с помощью Q_GLOBAL_STATIC?

Ответы [ 2 ]

0 голосов
/ 31 января 2019

Теперь он работает с небольшой модификацией в методе экземпляра с использованием 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;
}

Надеюсь, что это не приведет к другим проблемам ?

0 голосов
/ 31 января 2019

Можно совместно использовать глобальный статический экземпляр, но не так, как вы ожидаете.

Во-первых, Q_GLOBAL_STATIC - это просто макрос для создания локального экземпляра определенногокласс с безопасностью потоков.Таким образом, это в основном причудливый способ сделать:

static MyCass *instance() {
    static auto _instance = new MyClass();
    return _instance;
}
#define myGlobalStatic instance()

Преимущества макроса в том, что вы сохраняете код, что он ленив и что он имеет поточно-ориентированные конструкторы и деструкторы.Другими словами, создание локального экземпляра с этим макросом позволяет безопасно его использовать в глобальном масштабе.

Это означает, что даже если у вас в одной и той же исходной папке есть один и тот же оператор Q_GLOBAL_STATIC, будет несколькоразные экземпляры, все названы одинаково, но доступны только локально.

Это также относится к вашей конкретной идее: внутри singleton.o будет один такой экземпляр - однако, связав его с 3 различными двоичными файлами (app, p1, p2), вы в основном создаете 3 различных экземпляра,локально для каждого из двоичных файлов (поскольку компоновщик копирует его из объектного файла в двоичный файл для каждого из них)!Так что нет, ваша текущая идея не поделится экземпляром.

Единственный способ архивировать это - создать динамически связанную библиотеку, которая содержит один экземпляр и export функция получения от него, которая обеспечивает доступ к экземпляру.Свяжите два плагина и приложение с этой библиотекой, и во время выполнения будет только 1 единственный экземпляр (как часть библиотеки), к которому могут получить доступ все 3.

Для вашего проекта это означает, что у вас естьпревратить обычное в разделяемую библиотеку и связать приложение, 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 в исходном файле, который загружает плагины, или даже быть членом какого-то класса верхнего уровня.

...