起源:因为发现插件析构函数老是不被调用,最终注意到该bug。
简单陈述一些东西,不做加工
QTBUG-17458
该BUG内容:
bool QPluginLoader::unload ()
Unloads the plugin and returns true if the plugin could be unloaded; otherwise returns false.
This happens automatically on application termination, so you shouldn't normally need to call this function.
- 事实上,程序结束时,插件不会被unload,从而插件中root对象的析构函数也不会被调用。
官方尝试
- 2010年6月4日 397295f1a91c782f905374213b85ef1108c357e3,添加了程序退出时unload插件的代码
struct LibraryData {
LibraryData() : settings(0) { }
~LibraryData() {
foreach(QLibraryPrivate *lib, loadedLibs) {
lib->unload();
delete settings;
}
QSettings *settings;
LibraryMap libraryMap;
};
Q_GLOBAL_STATIC(LibraryData, libraryData)
它是借助于LibraryData的析构函数实现的。
- 2010年9月29日,6a1f951ff321982413b462b79293b273bbcc00de,对于一些老的插件,程序退出时的unload代码,会导致程序崩溃。故而删除了这部分代码。
LibraryData() : settings(0) { }
~LibraryData() {
delete settings;
- foreach(QLibraryPrivate *lib, loadedLibs) {
- lib->unload();
- }
}
插件构造、析构
看看插件的 new 和 delete 分别藏身何处
构造
所有的插件我们都会使用下面这个宏:
Q_EXPORT_PLUGIN2(PluginName, ClassName)
extern "C" Q_DECL_EXPORT QObject* qt_plugin_instance()
{
static QPointer<QObject> _instance;
if (!_instance)
_instance = new ClassName;
return _instance;
}
bool QLibraryPrivate::loadPlugin()
{
instance = (QtPluginInstanceFunction)resolve("qt_plugin_instance");
而后调用
QObject *QPluginLoader::instance()
{
...
return d->instance();
析构
调用unload时,先调用 delete 删除插件对象
bool QLibraryPrivate::unload()
{
if (!libraryUnloadCount.deref()) { // only unload if ALL QLibrary instance wanted to
if (instance)
delete instance();
if (unload_sys()) {
instance = 0;
pHnd = 0;
}
}
题外
乱七八糟,罗列与此:
QTextCodec
在QTextCodec相关的new、delete问题一则一文中,QTextCodec
插件所用的方法或许也可以借鉴一下。
不过看看QTBUG-4341,问题还是好复杂啊
static storage duration
C++中的Storage
Druation分4种:
- static storage duration
- thread storage duration
- automatic storage duration
- dynamic storage duration
由于thread那个目前尚没人用,所以static storage duration应该是最复杂的一个。也在Qt中也是大量使用的一个。
不过Google的C++
Style Guide却并不建议对类对象使用这个东西:
Static or global variables of class type are forbidden: they cause hard-to-find bugs due to indeterminate order of construction and destruction.
Objects with static storage duration, including global variables, static variables, static class member variables, and function static variables, must be Plain Old Data (POD): only ints, chars, floats, or pointers, or arrays/structs of POD.
The order in which class constructors and initializers for static variables are called is only partially specified in C++ and can even change from build to build, which can cause bugs that are difficult to find. Therefore in addition to banning
globals of class type, we do not allow static POD variables to be initialized with the result of a function, unless that function (such as getenv(), or getpid()) does not itself depend on any other globals.
Likewise, the order in which destructors are called is defined to be the reverse of the order in which the constructors were called. Since constructor order is indeterminate, so is destructor order. For example, at program-end time a static
variable might have been destroyed, but code still running -- perhaps in another thread -- tries to access it and fails. Or the destructor for a static 'string' variable might be run prior to the destructor for another variable that contains a reference to
that string.
As a result we only allow static variables to contain POD data. This rule completely disallows vector (use C arrays instead), or string (use const char []).
If you need a static or global variable of a class type, consider initializing a pointer (which will never be freed), from either your main() function or from pthread_once(). Note that this must be a raw pointer, not a "smart" pointer, since
the smart pointer's destructor will have the order-of-destructor issue that we are trying to avoid.
顺序
对于static storage duration的对象:
- 在全局范围中定义的对象,它的构造函数在文件中的所有函数执行之前调用。但如果一个程序中有多个文件,而不同的文件中都定义了全局对象,则这些对象的构造函数的执行顺序是不确定的。当main函数执行完毕或调用exit函数时,调用析构函数。
- 在函数中定义静态对象,则在程序第一次调用此函数建立对象时调用构造函数一次,在调用结束时对象并不释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用析构函数。
全局变量与动态库
C++ 标准对涉及到动态库的东西似乎没有任何规定。
-
http://msdn.microsoft.com/en-us/library/988ye33t.aspx提到:
Each time a new process attempts to use the DLL, the operating system creates a separate copy of the DLL's data: this is called process attach. The run-time library code for the DLL calls the constructors for all of the global objects, if any, and then calls
the DllMain function with process attach selected. The opposite situation is process detach: the run-time library code calls DllMain with process detach selected and then calls a list of termination functions, including atexit functions, destructors for the
global objects, and destructors for the static objects. Note that the order of events in process attach is the reverse of that in process detach.
参考
分享到:
相关推荐
由于`Widget`拥有`MyButton`,因此在`Widget`销毁之前,`MyButton`的析构函数`MyButton::~MyButton()`也会被调用,同样通过`qDebug()`输出一条信息,表明`MyButton`也在被销毁。这种行为清晰地展示了Qt中对象树和...
这个想法对于父对象是非QWidget类,是成立的,因为从上面分析一可以看出确实是先断开了所有信号槽的,但是对于父对象是QWidget类,是不对的,因为从上面分析二可以看出QWidget析构函数里就先删除孩子对象(此时信号...
通过QLibrary的load()方法,可以在运行时找到并加载dm.dll,然后使用QLibrary的resolve()方法查找并绑定插件中的函数指针,从而调用大漠插件的功能。 此外,"配套的工具软件"可能包括一些辅助工具,如插件的配置...
qt插件开发完整工程示例qt插件开发完整工程示例qt插件开发完整工程示例qt插件开发完整工程示例qt插件开发完整工程示例qt插件开发完整工程示例qt插件开发完整工程示例qt插件开发完整工程示例qt插件开发完整工程示例qt...
1. **QT调用JavaScript函数**: - 使用`QWebEnginePage::runJavaScript`方法可以执行JavaScript代码。例如,假设在网页中有一个名为`printMessage`的JavaScript函数,你可以这样调用它: ```cpp QWebEnginePage *...
例如,我们可以创建一个名为`IPlugin`的接口,包含`init`、`run`和`shutdown`等方法,这些方法将在插件被加载时被调用。 接下来,我们创建插件类,这些类继承自我们定义的`IPlugin`接口,并实现其中的虚函数。每个...
在QT中,插件技术允许开发者将应用程序的核心功能与可选的功能组件分离,这些组件可以单独进行更新、安装或卸载,而不影响主程序的运行。本项目“QT插件管理器框架-master”是基于Visual Studio 2019和QT5.13.1版本...
在"Qt-Qt插件技术-调用插件入门示例"中,我们将探讨如何创建和使用Qt插件。 首先,插件程序和调用插件的程序是两个独立的部分。插件程序是实现特定功能的动态链接库(DLL),它可以在运行时被主应用程序加载。调用...
- DLL接口设计:确保DLL的接口设计符合C风格,因为MFC是基于C++但不完全兼容C++的特性,特别是构造函数和析构函数不能直接跨DLL边界调用。 - `extern "C"`:为了跨编译器兼容性,所有导出的函数和变量应使用`...
在本主题中,我们将深入探讨如何基于QT和QML来实现插件的调用。 首先,了解QT插件的基本概念至关重要。QT插件是一种可动态加载的库,允许开发者扩展应用程序的功能,而无需重新编译和部署整个程序。这使得应用程序...
在本文中,我们将深入探讨Qt框架中的QGenericPlugin机制,以及如何在实际应用中实现主界面调用插件界面的功能。Qt是一个强大的跨平台应用程序开发框架,广泛应用于GUI设计和系统集成。QGenericPlugin是Qt提供的一种...
3. **头文件和JNI函数声明**:在Java中调用C++函数前,需要创建一个C/C++的头文件,声明将要调用的Qt函数。这些函数声明必须符合JNI的约定,例如使用`JNIEXPORT`和`JNICALL`宏。 4. **JNI方法定义**:在C++代码中,...
在windows下做应用开发时,经常需要多种不同的语言混合编程。... 这个Qt库是不需要界面的,只是一个单纯的库,提供方法给C#调用,完成指定的功能即可。 比如:视频加水印,图片模糊处理,图片镜像,视频特效等等。
我们将通过一个名为"Qt Plugin创建及调用"的案例来学习如何构建一个简单的Qt插件,并使用Visual Studio(VS)作为集成开发环境(IDE)搭建Qt应用程序框架。 首先,理解Qt插件的核心概念是至关重要的。Qt插件基于Qt...
本篇文章将深入探讨如何在Qt中调用JavaScript函数并传递参数,以实现更丰富的功能。 首先,Qt的Webkit模块是实现这一目标的关键。Qt Webkit是一个基于WebKit引擎的组件,它允许Qt应用渲染网页内容,并与网页进行...
QT设置回调函数给python调用——内置模块法demo
在本文中,我们将深入探讨Qt框架中的插件机制及其应用,通过一个具体的实例来解析如何在Qt中调用插件。Qt插件是Qt库提供的一种动态加载代码的能力,允许程序在运行时发现并使用可扩展的功能。这种设计模式使得Qt应用...
本篇文章将详细探讨在Qt环境中如何调用函数并返回多个值。 1. **使用结构体或类** 在C++中,我们可以创建一个结构体或类,将多个值封装在一起。例如,假设我们有三个需要返回的值`int a`, `QString b`, 和`bool c`...
6. **错误处理**:在调用库函数时,务必注意可能出现的错误,如找不到库、版本不兼容、函数调用失败等。使用异常处理或返回值检查来捕获并处理这些错误。 7. **调试**:在开发过程中,使用调试器(如Qt Creator内置...
简介:本人学习Qt一个星期了,利用Qt做的仿360界面,然后打包成动态库。 用C++的MFC对话框按钮调用Qt界面动态库,经测试成功。