单例的智能指针+宏的实现

如果要创建一个单例的数据库连接池 ConnectionPool,那么实现单例部分的代码和 ConfigUtil 的几乎一样,声明 private 的构造函数,拷贝构造函数,析构函数,赋值操作符,QScopedPointer instance,friend struct QScopedPointerDeleter,几乎完全一样的 getInstance() 等,这些代码几乎都是重复的,每个单例的类这些内容都重复一遍,违背了代码的复用原则。为了实现代码复用,可以用继承,函数,宏定义,模版等。对于单例,继承很难达到目的,这里我们选择使用宏来达到代码复用的目的,后面的章节会介绍使用模版的实现。

Singleton.h

把实现单例可复用的代码抽取出来定义为宏放在文件 Singleton.h 中。

#ifndef SINGLETON_H
#define SINGLETON_H

#include <QMutex>
#include <QScopedPointer>

// [[1]] 单例的主要内容声明与实现.
// Start of SINGLETON Declaration, Class 是类名
#define SINGLETON(Class)                        \
public:                                         \
    static Class& getInstance() {               \
        if (instance.isNull()) {                \
            mutex.lock();                       \
            if (instance.isNull()) {            \
                instance.reset(new Class());    \
            }                                   \
            mutex.unlock();                     \
        }                                       \
                                                \
        return *instance.data();                \
    }                                           \
                                                \
private:                                        \
    Class();                                    \
    ~Class();                                   \
    Class(const Class &other);                  \
    Class& operator=(const Class &other);       \
    static QMutex mutex;                        \
    static QScopedPointer<Class> instance;      \
    friend class QScopedPointer<Class>;         \
    friend struct QScopedPointerDeleter<Class>;


// End of SINGLETON Declaration

// [[2]] 静态对象的初始化
#define SINGLETON_STATIC_INITIALIZE(Class)      \
    QMutex Class::mutex;                        \
    QScopedPointer<Class> Class::instance;

#endif // SINGLETON_H

ConfigUtil.h

#ifndef CONFIGUTIL_H
#define CONFIGUTIL_H

#include "Singleton.h" // [[1]]
#include <QString>

class ConfigUtil {
    SINGLETON(ConfigUtil) // [[2]]

public:
    QString getDatabaseName() const;
};

#endif // CONFIGUTIL_H

ConfigUtil.cpp

#include "ConfigUtil.h"

SINGLETON_STATIC_INITIALIZE(ConfigUtil) // [[3]]

#include <QDebug>

ConfigUtil::ConfigUtil() {
    qDebug() << "ConfigUtil()";
}

ConfigUtil::~ConfigUtil() {
    qDebug() << "~ConfigUtil()";
}

QString ConfigUtil::getDatabaseName() const {
    return "Pandora";
}
现在实现单例的类,单例相关的代码,只需要:
  • 头文件 Singleton.h
  • 使用宏 SINGLETON
  • 使用宏 SINGLETON_STATIC_INITIALIZE

重复的模版代码都定义在宏里,编译的时候宏自动展开生成相应的代码,和没有使用宏的时候代码是完全一样的。

接下来实现一个单例的 ConnectionPool 是不是很简单了呢?具体代码就不写出来了,就当作给大家的作业,注意参考 ConfigUtil 里的标记为 [[1]][[2]] 和 [[3]] 的地方。

main.cpp

main.cpp 用于展示 ConfigUtil 的使用。

#include "ConfigUtil.h"
#include <QDebug>

int main(int argc, char *argv[]) {
    Q_UNUSED(argc)
    Q_UNUSED(argv)

    qDebug() << ConfigUtil::getInstance().getDatabaseName();
    qDebug() << ConfigUtil::getInstance().getDatabaseName();

    return 0;
}

输出:

ConfigUtil()
"Pandora"
"Pandora"
~ConfigUtil()

没有任何问题,这下心里有底了吧。

转载:http://qtdebug.com/Singleton-3-AutoPointerMacro.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值