当前位置: 首页 > news >正文

站长源码之家广东企业网站建设策划

站长源码之家,广东企业网站建设策划,梧州门户网站,网站创建软件Qt_一个由单例引发的崩溃 文章目录 Qt_一个由单例引发的崩溃摘要关于 Q_GLOBAL_STATIC代码测试布局管理器源码分析Demo 验证关于布局管理器析构Qt 类声明周期探索更新代码获取父类分析Qt 单例宏源码 关键字#xff1a; Qt、 Q_GLOBAL_STATIC、 单例、 UI、 崩溃 摘要 今… Qt_一个由单例引发的崩溃 文章目录 Qt_一个由单例引发的崩溃摘要关于 Q_GLOBAL_STATIC代码测试布局管理器源码分析Demo 验证关于布局管理器析构Qt 类声明周期探索更新代码获取父类分析Qt 单例宏源码 关键字 Qt、 Q_GLOBAL_STATIC、 单例、 UI、 崩溃 摘要 今天简直是令人心力交瘁的一天在公司被一个顽固的Bug纠缠了整整一天。一开始我对这个问题的认知并不深刻只是觉得有点小瑕疵于是比较轻松地着手解决。我开始摸索着定位问题态度上也没太在意毕竟在我看来这只是一场小小的技术挑战。 然而随着时间的推移我逐渐意识到问题的严重性。逐渐加深的烦躁和困扰让我开始感到不安。在一度对问题轻描淡写的态度下我终于被迫正视这个Bug所可能引发的连锁反应。随着这个问题的逐渐显露出其庞大的影响我仿佛看到了一个漩涡正在悄然蔓延着威胁着整个系统的稳定性。 随着深入的调查和排查我开始逐渐理解这个Bug的神秘本质而这个认识过程伴随着我的焦虑逐渐升温。我发现这并非是一个简单的技术故障而是一个可能牵动公司正常运营的重大问题。这时我终于感受到了来自责任的重压因为解决这个问题不仅关乎我的个人技术能力更涉及到公司业务的持续稳健。 最终当我对问题的了解达到顶峰时我不禁意识到这一天的崩溃并非仅限于我的个人情绪更是对整个系统运行稳定性的一次极大考验。这场对抗Bug的战斗让我感受到了技术领域的不可预测性和挑战性也让我更加深刻地明白在这个领域中的学无止境。 关于 Q_GLOBAL_STATIC 我在创建单例上偷了懒使用了Qt Q_GLOBAL_STATIC宏来创建单例。关于Q_GLOBAL_STATIC的解释如下 Q_GLOBAL_STATIC 是 Qt 框架中用于创建全局静态变量的宏。这个宏的目的是确保在多线程环境下安全地初始化和访问静态变量。在 C 中全局静态变量的初始化顺序可能会带来一些问题特别是在多线程环境下。 使用 Q_GLOBAL_STATIC 宏Qt 提供了一种线程安全的机制来创建全局静态变量。这个宏可以确保静态变量只在第一次访问时被初始化而且在初始化过程中是线程安全的。 具体用法如下 Q_GLOBAL_STATIC(Type, variable)其中Type 是要创建的静态变量的类型variable 是变量的名称。 举例说明 #include QGlobalStaticclass MyClass { public:MyClass() {// 构造函数}// 其他成员函数和数据成员 };Q_GLOBAL_STATIC(MyClass, myGlobalInstance)在上面的例子中myGlobalInstance 就是一个全局静态变量它的类型是 MyClass。使用 Q_GLOBAL_STATIC 宏Qt 会在需要时确保 myGlobalInstance 被安全地初始化并在整个程序运行期间保持其存在。 这种机制的好处是在多线程环境下多个线程可以同时访问 myGlobalInstance而不必担心因为初始化顺序而导致的问题。Qt 在内部使用了一些技巧比如使用双重检查锁定double-checked locking等以确保在多线程环境下的性能和正确性。 代码测试 所以按照上面的解释我使用Q_GLOBAL_STATIC来创建一个单例应该是没有问题的。但是。 下面看下的Demo 代码 头文件 #ifndef FORM_H #define FORM_H#include QWidgetnamespace Ui { class Form; }class Form : public QWidget {Q_OBJECTpublic:explicit Form(QWidget *parent nullptr);static Form* getInstance();~Form();private:Ui::Form *ui; };#endif // FORM_H 源文件 #include form.h #include ui_form.h Q_GLOBAL_STATIC(Form,m_Form) Form::Form(QWidget *parent) :QWidget(parent),ui(new Ui::Form) {ui-setupUi(this); }Form *Form::getInstance() {return m_Form; }Form::~Form() {delete ui; } 调用文件 #include mainwindow.h #include ui_mainwindow.h #include form.h MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui-setupUi(this);ui-verticalLayout-addWidget(Form::getInstance());}MainWindow::~MainWindow() {delete ui; } 布局管理器源码分析 看到这里不知道你发现问题所在了没有呢。其实到这里程序运行什么都都是没有问题的就是不要退出程序因为一旦退出程序就会遇到崩溃问题。那么开始我一度以为是使用了布局管理器导致的这个问题但是我看了源码也却突然发现布局管理器是不会对其管理的控件进行资源释放的部分源码如下我这里就合并显示了。 QBoxLayoutPrivate::~QBoxLayoutPrivate() { }/*!Destroys this box layout.The layouts widgets arent destroyed. */ QHBoxLayout::~QHBoxLayout() { }/*!The layouts widgets arent destroyed. */ QVBoxLayout::~QVBoxLayout() { }Demo 验证 保险起见我还特意谷歌翻译了一下Destroys this box layout.The layouts widgets arent destroyed.里面明确说明布局会破坏但是里面的控件不会释放。所谓问题来到底是哪里的问题了我尝试了另一种写法代码如下希望你还可以跟得上 #include mainwindow.h #include ui_mainwindow.h #include form.h MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui-setupUi(this);Form * temp Form::getInstance();temp-setParent(this);temp-show(); }MainWindow::~MainWindow() {delete ui; }这样我得到的结果同样是崩溃的析构函数如下图所示 关于布局管理器析构 正当我一头雾水的手我随机搜了一下Qt 布局管理器在析构是会析构子控件吗这个问题得到的回答如下 在 Qt 中布局管理器在析构时通常不会主动析构其管理的子控件。布局管理器负责管理控件的位置和大小而控件的生命周期管理通常是由其父控件负责的。 当一个 QWidget 对象可能是窗口或其他容器控件被析构时它会负责删除其子控件。这是因为 QWidget 继承自 QObject而 QObject 有一个父子对象关系系统负责自动管理子对象的内存。 布局管理器在 Qt 中主要用于确定子控件的布局而不是控制它们的生命周期。因此当布局管理器本身被析构时它不会主动销毁其管理的子控件。子控件的析构通常是由其父控件来处理。 如果你希望在删除布局管理器的同时也删除其管理的子控件你需要手动迭代子控件并将其删除或者使用智能指针等工具来管理控件的生命周期。这可以确保在删除布局管理器时相关的子控件也会被正确地释放。 总的来说Qt 的布局管理器并不负责子控件的析构而是留给控件的父对象来管理。 结合上面对布局管理器源码的分析可以看到我们的崩溃不是有布局管理器引起的而是被父类析构析构了。 Qt 类声明周期探索 本着刨根问题的原则我有问了另一个问题设置了布局管理器就等于设置了父类吗 在 Qt 中设置了布局管理器并不等同于设置了父类。虽然布局管理器通常是作为容器控件的子对象来管理的但它们在概念上是不同的。 父子关系 当你将一个控件例如 QWidget设置为另一个控件的子控件时它们建立了父子关系。这样做的话父控件会负责管理子控件的生命周期包括在父控件销毁时自动删除子控件。布局管理器是一种机制用于控制子控件的布局但它们通常不会成为父控件。布局管理器可以安排子控件的位置和大小但并不会负责管理它们的生命周期。 布局管理器的作用 布局管理器是用来管理布局的工具。它们通常被设置在容器类控件上比如 QWidget、QMainWindow、QDialog 等。布局管理器负责决定子控件的排列方式但不负责管理它们的析构。 下面是一个简单的例子演示了如何在 QWidget 中使用布局管理器 #include QHBoxLayout #include QPushButton #include QWidgetint main(int argc, char *argv[]) {QApplication app(argc, argv);QWidget *mainWidget new QWidget;QHBoxLayout *layout new QHBoxLayout(mainWidget);QPushButton *button1 new QPushButton(Button 1);QPushButton *button2 new QPushButton(Button 2);layout-addWidget(button1);layout-addWidget(button2);mainWidget-setLayout(layout);mainWidget-show();return app.exec(); }在这个例子中mainWidget 是一个 QWidget而 layout 是一个 QHBoxLayout。布局管理器 layout 被设置为 mainWidget 的布局管理器。然而mainWidget 仍然是这两个按钮的父控件而不是布局管理器。 总的来说在设置布局管理器时确保理解父子关系的变化并注意生命周期管理的责任。 更新代码获取父类 虽然回答的不是那么一回事但是还是启发了所以我对我的代码做了一点更新如下 #include mainwindow.h #include ui_mainwindow.h #include form.h #include QDebug MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui-setupUi(this);Form * temp Form::getInstance();ui-verticalLayout-addWidget(temp);qDebug() temp-parent()- temp-parent() endl temp-parent()-parent()- temp-parent()-parent() endl this- this endl this-parent()- this-parent() endl ui-verticalLayout-parent() ui-verticalLayout-parent(); }MainWindow::~MainWindow() {delete ui; } 得到打印信息如下 temp-parent()- QWidget(0x948920, name centralwidget) temp-parent()-parent()- MainWindow(0x8ffd20, name MainWindow) this- MainWindow(0x8ffd20, nameMainWindow) this-parent()- QObject(0x0) ui-verticalLayout-parent() QWidget(0x948920, name centralwidget)这下基本明白了其实对象的声明周期在Qt里面还是受气父控件的控制而并非是布局管理器今天我之所碰巧解决了这个Bug仅仅是因为当我们吧控件添加到布局管理器时。不管理器把他的费空间做了传递、现在终于明白了。 分析Qt 单例宏源码 那么还需要解决另一个问题就是我的单例宏做了什么。 #define Q_GLOBAL_STATIC(TYPE, NAME) \Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ())#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \namespace { namespace Q_QGS_ ## NAME { \typedef TYPE Type; \QBasicAtomicInt guard Q_BASIC_ATOMIC_INITIALIZER(QtGlobalStatic::Uninitialized); \Q_GLOBAL_STATIC_INTERNAL(ARGS) \} } \static QGlobalStaticTYPE, \Q_QGS_ ## NAME::innerFunction, \Q_QGS_ ## NAME::guard NAME; #if defined(Q_COMPILER_CONSTEXPR) # define Q_BASIC_ATOMIC_INITIALIZER(a) { a } #else # define Q_BASIC_ATOMIC_INITIALIZER(a) { ATOMIC_VAR_INIT(a) } #endif #define Q_GLOBAL_STATIC_INTERNAL(ARGS) \Q_GLOBAL_STATIC_INTERNAL_DECORATION Type *innerFunction() \{ \struct HolderBase { \~HolderBase() noexcept \{ if (guard.loadRelaxed() QtGlobalStatic::Initialized) \guard.storeRelaxed(QtGlobalStatic::Destroyed); } \}; \static struct Holder : public HolderBase { \Type value; \Holder() \noexcept(noexcept(Type ARGS)) \: value ARGS \{ guard.storeRelaxed(QtGlobalStatic::Initialized); } \} holder; \return holder.value; \} #else // We dont know if this compiler supports thread-safe global statics // so use our own locked implementationQT_END_NAMESPACE #include QtCore/qmutex.h #include mutex QT_BEGIN_NAMESPACE#define Q_GLOBAL_STATIC_INTERNAL(ARGS) \Q_DECL_HIDDEN inline Type *innerFunction() \{ \static Type *d; \static QBasicMutex mutex; \int x guard.loadAcquire(); \if (Q_UNLIKELY(x QtGlobalStatic::Uninitialized)) { \const std::lock_guardQBasicMutex locker(mutex); \if (guard.loadRelaxed() QtGlobalStatic::Uninitialized) { \d new Type ARGS; \static struct Cleanup { \~Cleanup() { \delete d; \guard.storeRelaxed(QtGlobalStatic::Destroyed); \} \} cleanup; \guard.storeRelease(QtGlobalStatic::Initialized); \} \} \return d; \} #endif让我们稍作翻译 这段宏定义了一个模板化的全局静态变量创建机制通过 Q_GLOBAL_STATIC_INTERNAL 宏可以方便地创建一个全局静态变量。这个机制使用了 C11 的特性包括 noexcept 说明符和内存模型的一些操作。 让我们逐步解释这个宏的各个部分 Q_GLOBAL_STATIC_INTERNAL(ARGS): 这是主要的宏定义用于创建全局静态变量。ARGS 是传递给 Type 类型构造函数的参数。 Q_GLOBAL_STATIC_INTERNAL_DECORATION: 这是一个在宏中使用的修饰符可能是空的取决于编译器对 C11 特性的支持情况。 Type *innerFunction(): 这是一个内部的静态函数负责实际创建和返回全局静态变量的指针。它使用了一个内部的 Holder 类以确保在全局静态变量的析构期间正确地管理生命周期。 struct HolderBase: 这是一个基础结构其中的析构函数负责在全局静态变量被销毁时检查并更新一个状态标志。这个标志在构造时被设置为 Initialized而在析构时被设置为 Destroyed。 struct Holder : public HolderBase: 这是一个派生自 HolderBase 的结构。它包含了具体的 Type 类型的实例value并在构造函数中将状态标志设置为 Initialized。这确保在全局静态变量的生命周期内HolderBase 的析构函数将被正确调用以更新状态标志。 整个机制的目的是确保在多线程环境下全局静态变量的创建是线程安全的。通过在 HolderBase 的析构函数中检查状态标志可以防止在全局静态变量析构时重复析构。 这是一个比较复杂的实现主要是为了保证全局静态变量的正确创建和销毁并且在多线程环境下能够安全使用。 所以现在应该明白了这就是资源双重释放了未来的你加油。
http://www.hkea.cn/news/14262049/

相关文章:

  • 东营本地网站制作公司南宁建设公司网站
  • 上海最专业的网站建设公司优秀的wordpress涉及
  • 网站建设规划书模板岳阳网站建设网站
  • 垂直电商网站建设方案wordpress商品系统
  • 2018年靖边建设项目招投标网站网站大全app下载
  • 百度做网站的遵义网址
  • 达内网站开发培训学做美食的视频网站
  • 美容院门户网站开发外贸网站推广上海
  • 廊坊做网站的哪最多wordpress register_form
  • 成都市建设厅网站查询企业网站制作费用
  • 小白怎样建设公司网站iis7 网站 目录
  • 如何申请自己的网站如何防止网站被注册
  • 怎么查看网站外链嘉兴网站建设推广
  • 网站建设与管理吴振峰ppt网络营销的广告形式有哪些
  • 做网站搜索排名经过开发建设 网站上线了
  • 长春企业网站排名优化wordpress怎么用代码编辑器
  • 天津重型网站建设风格linux wordpress mysql 配置
  • 宝安网站建设哪家好产品宣传推广方式有哪些
  • 网站标签管理纯图片网站源码
  • 电子商务网站模板 html谷歌浏览器官网下载手机版
  • 嘉兴php网站开发网站收录慢
  • 电子商务网站费用谷歌seo服务
  • 网站建设前期需要做出的准备专业网站建设制作价格低
  • 做淘宝有哪些推广网站泰安有口碑的网站建设
  • 智冠宝企业网站管理系统如何开发一款游戏
  • 电力建设期刊网站投稿做网站需要自己研发吗
  • 长沙网站优化方式佛山建设网站
  • 常州网站制作费用wordpress修改上传文件路径
  • 网站建设支付安全辽宁建设工程信息网新入口
  • 网站建设与发布建设生鲜网站价格表