若该文为原创文章,转载请注明原文出处
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/80046081
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究
红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…(点击传送门)
Qt开发专栏:实用技巧(点击传送门)
需求
Qt常需要一个类,全局调用,是设计模式中的单例模式。
单例模式
单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。
显然单例模式的要点有三个;
- 一是某个类只能有一个实例;
- 二是它必须自行创建这个实例;
- 三是它必须自行向整个系统提供这个实例。
Qt单例模式示例模板(此版本重大bug)
使用DbService::instance()全局获取该对象
头文件
#ifndef DBSERVICE_H #define DBSERVICE_H #include <QObject> #include <QMutex> #include <QMutexLocker> class DbService : public QObject { Q_OBJECT public: explicit DbService(QObject *parent = 0); public: static DbService * instance(); signals: public slots: protected: private: static DbService *_pInstance; static QMutex _mutex; }; #endif // DBSERVICE_H
源文件(存在bug)
#include "DbService.h" DbService * DbService::_pInstance = 0; QMutex DbService::_mutex; DbService::DbService(QObject *parent) : QObject(parent) { } DbService * DbService::instance() { if(!_pInstance) { QMutexLocker lock(&_mutex); if(!_pInstance) { _pInstance = new DbService(); } } return _pInstance; }
bug(感谢网友大神:火龙 的帮助)
_pInstance = new DbService();
1. 申请DbService的内存
2. 在申请的内存上构造DbService
3. 将_pInstance指针指向这个内存
这个new有这么三步
编译器可能是132这么执行的,多个线程第一次同时使用时,可能出现野指针,即编译器先指向内存(准备第三步构造)时,另一个线程获取,则出现野指针,运行出现段错误。
源文件(修复完bug)
#include "DbService.h" DbService * DbService::_pInstance = 0; QMutex DbService::_mutex; DbService::DbService(QObject *parent) : QObject(parent) { } DbService * DbService::instance() { if(!_pInstance) { QMutexLocker lock(&_mutex); if(!_pInstance) { DbService *pInstance = new DbService(); // 修改处 _pInstance = pInstance; // 修改处 } } return _pInstance; }
Qt单例模式示例模板(修复bug后的单例模式代码2:使用原子caozuo)
头文件
#ifndef DBSERVICE_H #define DBSERVICE_H #include <QObject> #include <QMutex> #include <QMutexLocker> class DbService : public QObject { Q_OBJECT public: explicit DbService(QObject *parent = 0); public: static DbService *getInstance(); signals: public slots: protected: private: static QAtomicPointer<DbService> _instance; static QMutex _mutex; }; #endif // DBSERVICE_H
源文件
#include "DbService.h" QAtomicPointer<DbService> DbService::_instance = 0; QMutex DbService::_mutex; DbService::DbService(QObject *parent) : QObject(parent) { } DbService * DbService::instance() { #ifndef Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE if(!QAtomicPointer::isTestAndSetNative())//运行时检测 qDebug() << "Error: TestAndSetNative not supported!"; #endif //使用双重检测。 /*! testAndSetOrders操作保证在原子操作前和后的的内存访问 * 不会被重新排序。 */ if(_instance.testAndSetOrdered(0, 0))//第一次检测 { QMutexLocker locker(&mutex);//加互斥锁。 _instance.testAndSetOrdered(0, new DbService);//第二次检测。 } return _instance; }
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/80046081