注意

  • 换行需添加换行符 “\”
  • 宏中不能使用 // 添加注释,注释必须写在续行符("")的前面,使用 /* — */进行注释


#ifndef SINGLETON_H
#define SINGLETON_H

#include <QMutex>
#include <QScopedPointer>

/**
* 使用方法:
* 1. 定义类为单例:
* class ConnectionPool {
* SINGLETON(ConnectionPool) // Here
* public:
*
* 2. 获取单例类的对象:
* Singleton<ConnectionPool>::getInstance();
* ConnectionPool &pool = Singleton<ConnectionPool>::getInstance();
* 注意: 如果单例的类需要释放的资源和 Qt 底层的信号系统有关系,例如 QSettings,QSqlDatabase 等,
* 需要在程序结束前手动释放(也就是在 main() 函数返回前调用释放资源的函数,参考 ConnectionPool 的调用),
* 否则有可能在程序退出时报系统底层的信号错误,导致如 QSettings 的数据没有保存。
*/
template <typename T>
class Singleton {
public:
static T& getInstance();

Singleton(const Singleton &other);
Singleton<T>& operator=(const Singleton &other);

private:
//同步锁
static QMutex mutex;
//智能指针,只在该作用域存在,一旦出该作用域,就会自动销毁
static QScopedPointer<T> instance;
};

/*-----------------------------------------------------------------------------|
| Singleton implementation |
|----------------------------------------------------------------------------*/
template <typename T> QMutex Singleton<T>::mutex;
template <typename T> QScopedPointer<T> Singleton<T>::instance;

template <typename T>
T &Singleton<T>::getInstance()
{
if (instance.isNull()) {
mutex.lock();
if (instance.isNull()) {
//reset():delete目前指向的对象,调用其析构函数,将指针指向另一个对象other,所有权转移到other
instance.reset(new T());
}
mutex.unlock();
}
/**
* 获取智能指针动态创建的对象的指针有两种方法:QScopedPointer#data() 和 QScopedPointer#take()
* T *QScopedPointer::data() const返回指向对象的常量指针,QScopedPointer仍拥有对象所有权。
* 所以通过data()返回过后就被自动删除了,从而导致mian函数中的p1变成了野指针,程序崩溃.
* 使用T *QScopedPointer::take()也是返回对象指针,但QScopedPointer不再拥有对象所有权,而
* 是转移到调用这个函数的caller,同时QScopePointer对象指针置为NULL
*/
return *instance.data();
}

/*-----------------------------------------------------------------------------|
| Singleton Macro |
|----------------------------------------------------------------------------*/

/**
* QScopedPointerDeleter 是 QScopedPointer 的默认实现,使用delete删除指针
* 宏中不能使用 // 添加注释,换行续添加换行符 “\”
*/
#define SINGLETON(Class) \
private: \
Class(); \
~Class(); \
Class(const Class &other); \
Class& operator=(const Class &other); \
friend class Singleton<Class>; /* 注释必须写在续行符("\")的前面 */ \
friend struct QScopedPointerDeleter<Class>;/* 末尾注释不需要加续行符 */
#endif // DBUTIL_H