【问题标题】:Why isn't the destructor called for my dynamically-loaded Qt plugin class?为什么我的动态加载的 Qt 插件类没有调用析构函数?
【发布时间】:2013-09-30 09:53:07
【问题描述】:

在我的 C++ Qt 应用程序(一个字典查找/测验程序)中,我使用插件为人们可能想要添加和使用的所有可能的语言提供功能。这些插件是在运行时从主窗口小部件的构造函数中搜索和加载的:

void MainForm::loadPlugins()
{
    QDir curDir;
    QStringList pluginFilter;
    pluginFilter << "*_plugin.dll";
    QStringList pluginFiles = curDir.entryList(pluginFilter, QDir::Files);

    for (int i = 0; i < pluginFiles.size(); ++i)
    {
        const QString &pluginFile = pluginFiles.at(i);
        QPluginLoader loader(pluginFile);
        DictionaryPlugin *plug = qobject_cast<DictionaryPlugin*>(loader.instance());
        if (plug)
        {
            plugins_.append(plug);
        }
    }
}

我曾经认为我应该自己销毁加载的插件,所以我迭代了~MainForm()中的plugins_(指针的QList),依次删除它们。后来我从QPluginLoader 的文档中发现我不应该这样做。此外,它还引起了一个奇怪的错误,导致程序在关闭时冻结(但仅在调试器下运行后),所以它显然有问题。

我从~MainForm() 中删除了删除部分,一切似乎都正常,除了我注意到插件的析构函数没有被调用。我依靠那些在应用程序终止时保存一些特定于插件的设置,否则我不会注意到。我在其中一个析构函数上放了一个断点,而调试器从未进入它。

这是插件的概要:

// dict_plugin.h
class DictionaryPlugin
{
public:
    virtual ~DictionaryPlugin() {}

    virtual QString name() const = 0;
    virtual QString language() const = 0;
    /* ... */
};

Q_DECLARE_INTERFACE(DictionaryPlugin, "DictionaryPlugin")

// jp_plugin.h
class JpPlugin : public QObject, public DictionaryPlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "JpPlugin")
    Q_INTERFACES(DictionaryPlugin)

public:
    JpPlugin();
    virtual ~JpPlugin();

    virtual QString name() const { return QString("Japanese plugin v1.0"); }
    virtual QString language() const { return QString("Japanese"); }
    /* ... */
};

// jp_plugin.cpp
JpPlugin::~JpPlugin()
{
    saveSettings();

    delete dictWidget_;
    delete settWidget_;

    delete kanjiDialog_;
    delete wordDialog_;
    delete radicalDialog_;
}

我的问题是,插件是如何销毁的?显然,当我的程序终止后操作系统回收内存时,它们必须如此。为什么省略了析构函数?还有其他方法可以让我释放他们吗?也许在MainForm 类中保留原始QPluginLoader 对象,然后在析构函数中手动保留unload() 它们?析构函数还负责销毁插件拥有的一些 QDialogs 和 UI 小部件。这是否意味着程序退出时我有泄漏?

谢谢!

更新: 我尝试为每个插件存储指向 QPluginLoaders 的指针。在~MainForm() 中,我遍历它们,调用unload()deleteing 他们。工作正常,除了冻结错误又回来了。当我关闭应用程序时,窗口消失了,但程序继续在调试器中运行。我可以暂停它,但堆栈只显示 ntdll.dll 中的一些身份不明的入口点。似乎没有什么马上不好的事情发生,正常运行时甚至都看不到,但不知怎的让我感到不安。

UPDATE2:我让程序运行在冻结状态(忘记停止它),发现它在一段时间后正常终止;它只花了大约 20 多秒的时间。现在我非常惊讶。这是什么原因造成的?

【问题讨论】:

    标签: c++ qt plugins dll destructor


    【解决方案1】:

    我在 Google 上找到了这个:

    QPluginLoader 有自己的 ref 计数,当 已为每个 QPluginLoader 实例调用了 unload() 有一个句柄。 unload() 不会在 QPluginLoader 析构函数,因此永远不会自动删除插件。

    它可以追溯到 2010 年,但也许您应该尝试保留对加载程序的引用并在程序结束时手动调用卸载。

    这里是文章的链接:

    How to unload modules in Qt

    【讨论】:

    • 我刚刚这样做了,但是冻结错误又回来了。更新 Q。
    • 冻结错误是否可能是由于您在析构函数中执行的操作(例如在 saveSettings() 中)?
    • 我不这么认为;我将析构函数中的所有内容都注释掉了,但它仍然冻结。
    • 似乎冻结根本不是冻结,只是滞后;请参阅更新 2。它与插件的关系是我无法理解的。
    • 好的,看起来这是我的应用程序中与插件引擎无关的东西,可能是某处的内存损坏干扰了插件的破坏。 Q 是关于处理插件的正确方法,你交付了,所以我接受了。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    • 2017-03-22
    • 1970-01-01
    • 2018-09-24
    相关资源
    最近更新 更多