QT源码解析--插件类QPluginLoader单例设计

文章详细分析了QT框架中QPluginLoader实现单例模式的源码过程,从instance方法到QLibraryPrivate的findOrCreate,再到静态变量qt_library_data_once的使用,揭示了为何不能创建QPluginLoader的多个实例。解决方法是利用插件接口的newInstance方法来创建多个对象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、问题描述

当插件名称一样时,new的不同QPluginLoader对象instance方法获取实例地址是一样的,这样的话就无法创建多个实例。

QPluginLoader *loader = new QPluginLoader("Yolo5Plugin.dll");
QPluginLoader *loader2 = new QPluginLoader("Yolo5Plugin.dll");

二、源码解析

为了研究QPluginLoader为何是个单例模式,下面将一层一层剖析QT源码

1、首先查看instance实现代码,这里还看不出单例模式,但返回值是从d指针获取的,说明d指针可能是单例,d指针对应类为QLibraryPrivate。

QObject *QPluginLoader::instance()
{
    if (!isLoaded() && !load())
        return 0;
    if (!d->inst && d->instance)
        d->inst = d->instance();
    return d->inst.data();
}
 QLibraryPrivate *d;

 2、d指针是如何赋值的? 可以发现是在setFileName函数中赋值的,来源于QLibraryPrivate::findOrCreate

void QPluginLoader::setFileName(const QString &fileName)
{
#if defined(QT_SHARED)
    QLibrary::LoadHints lh = QLibrary::PreventUnloadHint;
    if (d) {
        lh = d->loadHints();
        d->release();
        d = 0;
        did_load = false;
    }

    const QString fn = locatePlugin(fileName);

    d = QLibraryPrivate::findOrCreate(fn, QString(), lh);
    if (!fn.isEmpty())
        d->updatePluginState();

#else
    if (qt_debug_component()) {
        qWarning("Cannot load %s into a statically linked Qt library.",
            (const char*)QFile::encodeName(fileName));
    }
    Q_UNUSED(fileName);
#endif
}

 3、接下来进入QLibraryPrivate::findOrCreate源码,发现返回值来源与instance()函数

QLibraryPrivate *QLibraryPrivate::findOrCreate(const QString &fileName, const QString &version,
                                               QLibrary::LoadHints loadHints)
{
    return QLibraryStore::findOrCreate(fileName, version, loadHints);
}
inline QLibraryPrivate *QLibraryStore::findOrCreate(const QString &fileName, const QString &version,
                                                    QLibrary::LoadHints loadHints)
{
    QMutexLocker locker(&qt_library_mutex);
    QLibraryStore *data = instance();

    // check if this library is already loaded
    QLibraryPrivate *lib = 0;
    if (Q_LIKELY(data)) {
        lib = data->libraryMap.value(fileName);
        if (lib)
            lib->mergeLoadHints(loadHints);
    }
    if (!lib)
        lib = new QLibraryPrivate(fileName, version, loadHints);

    // track this library
    if (Q_LIKELY(data) && !fileName.isEmpty())
        data->libraryMap.insert(fileName, lib);

    lib->libraryRefCount.ref();
    return lib;
}

 4、再进入instance()函数,返回值来源与变量qt_library_data,而qt_library_data定义为static,这里还使用了静态变量qt_library_data_once保证了单例特性。在上一步骤中使用了加锁机制,所以还是一个线程安全的单例模式。

// must be called with a locked mutex
QLibraryStore *QLibraryStore::instance()
{
    if (Q_UNLIKELY(!qt_library_data_once && !qt_library_data)) {
        // only create once per process lifetime
        qt_library_data = new QLibraryStore;
        qt_library_data_once = true;
    }
    return qt_library_data;
}
static QBasicMutex qt_library_mutex;
static QLibraryStore *qt_library_data = 0;
static bool qt_library_data_once;

三、如何才能创建多个实例?

获取 instance 的对象后,对象提供一个创建该对象的方法。

DefectInterface *Yolo5Plugin::newInstance()
{
    return new Yolo5Plugin();
}
DefectInterface *base =  qobject_cast<DefectInterface *>(loader->instance());
DefectInterface *defect1 = base->newInstance();
DefectInterface *defect2 = base->newInstance();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jason~shen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值