QPluginLoader::instance() 的无限递归循环

Infinite recursive loop with QPluginLoader::instance()

我有一个概念上的问题想讨论一下。首先,我制作了一个插件加载自动系统,其工作原理如下:

1) 给出了要查找的插件文件名或路径。

2) 然后可以使用接口指针对其进行查询,并在找到时将其转换为合适的插件(可选地附加条件)。

查找实现的模板函数如下所示:

template<tInterface> tInterface *implementation(const Requirements &req = Requierements())
{
    tInterface *interface = nullptr;

    for(QPluginLoader *loader : loaders(req)) //returns list of plugins that meet requirements in req
    {
        interface = qobject_cast<tInterface*>(loader.instance())

        if(interface)
            break;
    }

    return interface;
}

根据 Qt 文档,插件 instance()(返回根组件)应该在所有操作同一文件的 QPluginLoader 对象之间 "shared"。好吧,我发现事实并非如此。当从插件构造函数(或在根构造函数调用的任何构造函数)中调用它时,上面的代码将无限循环。因为这样的调用将实例化同一个插件(以及其他插件)来测试请求的实现,这将触发另一个调用等等。只有在插件构造函数之外调用时它才能正常工作...

我正在尝试找出一种解决方案,即使在插件的构造函数中也能使用它。到目前为止,我想不出一种方法或机制来停止循环,因此我的问题在这里。感谢您的任何想法!

好的,答案很简单。当前调用 instance() 的 QPluginLoader 对象必须在调用 instance() 之前 "locked" 以便在第一次调用完成之前禁止对其实例的后续调用 - 有点像互斥行为。这可以防止在同一 QPluginLoader 上对 instance() 的调用中调用 instance() 所描述的问题(发生是因为搜索所有插件以寻找接口的可能实现,请参阅 OP 了解执行此操作的功能) .

我通过跟踪 "in use" 在 instance() 完成后释放它们的 QPluginLoader 对象来完成它。这允许我在其他插件的构造函数中请求插件,唯一的限制是我不能在加载层次结构中请求相同的插件或任何 "parent" 插件:

如果插件 X 的构造函数请求插件 Y,而插件 Y(在其构造函数中)请求插件 Z,则 Z 不能在其自己的构造函数中请求 Y 或 X(并且 Y 不能请求 X)。此类尝试将无法返回 nullptr 接口。

为了完整起见,这里是修改后的函数:

template<tInterface> tInterface *implementation(const Requirements &req = Requierements())
{
    tInterface *interface = nullptr;

    for(QPluginLoader *loader : loaders(req)) 
    //loaders() returns list of plugins that meet requirements in req
    //AND ARE NOT PRESENT IN m_Locked
    {
        m_Locked << loader;
        interface = qobject_cast<tInterface*>(loader.instance())
        m_Locked.removeOne(loader);

        if(interface)
            break;
    }

    return interface;
}