单例的智能指针实现

前面提出了一个问题:可不可以不需要我们手动的调用 release() 函数,程序结束前自动的删除单例类的对象呢?答案是可以,使用智能指针可以达到这个目的,这里我们使用的是 Qt 的 QScopedPointer 来实现,也可以使用标准的 C++ 的智能指针。

Qt 的帮助文档里对 QScopedPointer 的描述是

The QScopedPointer class stores a pointer to a dynamically allocated object, and deletes it upon destruction.

也就是说,QScopedPointer 持有一个指针,当 QScopedPointer 变量超出它的作用域后,就会自动的调用 delete 删除它持有的指针对象。我们在单例类 ConfigUtil 里定义了一个静态的 QScopedPointer 的变量 instance,其持有 ConfigUtil 类的指针对象,程序结束的时候会自动析构 instance 而析构单例类的指针对象,所以就不需要在程序结束的时候手动的调用 release() 函数了。

关于 QScopedPointer 更多的信息请参考 Qt 的帮助文档,里面有很多例子,对理解 QScopedPointer 很有帮助,可以如下图在 QtCreator 里搜索: 

ConfigUtil.h

#ifndef CONFIGUTIL_H
#define CONFIGUTIL_H

#include <QString>
#include <QMutex>
#include <QScopedPointer>

class ConfigUtil {
public:
    QString getDatabaseName() const;

    static ConfigUtil& getInstance();
    static void release();

private:
    ConfigUtil();
    ~ConfigUtil();
    ConfigUtil(const ConfigUtil &other);
    ConfigUtil& operator=(const ConfigUtil &other);

    static QMutex mutex;
    static QScopedPointer<ConfigUtil> instance;
    friend struct QScopedPointerDeleter<ConfigUtil>;
};

#endif // CONFIGUTIL_H

static QScopedPointer<ConfigUtil> instance 创建的静态变量 instance 会在程序结束前析构(在main() 函数返回之后),调用 delete 删除它持有的 ConfigUtil 的指针对象。

也许你会觉得有点奇怪的是 friend struct QScopedPointerDeleter<ConfigUtil>,为什么是声明 QScopedPointerDeleter 为 friend struct,而不是声明 QScopedPointer 为 friend class?

这和 QScopedPointer 的实现有关,QScopedPointer 被析构时不是直接在它的析构函数里调用 delete 删除它持有的指针对象,而是使用它的 Cleanup Handler 来删除,默认是 QScopedPointerDeleter,在 QScopedPointer 的帮助里有具体的说明:

Custom Cleanup Handlers

Arrays as well as pointers that have been allocated with malloc must not be deleted using delete. QScopedPointer's second template parameter can be used for custom cleanup handlers.

The following custom cleanup handlers exist:

  • QScopedPointerDeleter - the default, deletes the pointer using delete
  • QScopedPointerArrayDeleter - deletes the pointer using delete []. Use this handler for pointers that were allocated with new [].
  • QScopedPointerPodDeleter - deletes the pointer using free(). Use this handler for pointers that were allocated with malloc().
  • QScopedPointerDeleteLater - deletes a pointer by calling deleteLater() on it. Use this handler for pointers to QObject's that are actively participating in a QEventLoop.

You can pass your own classes as handlers, provided that they have a public static function void cleanup(T *pointer).

ConfigUtil.cpp

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

QMutex ConfigUtil::mutex;
QScopedPointer<ConfigUtil> ConfigUtil::instance;

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

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

QString ConfigUtil::getDatabaseName() const {
    return "Verbose";
}

ConfigUtil& ConfigUtil::getInstance() {
    if (instance.isNull()) {
        mutex.lock();
        if (instance.isNull()) {
            instance.reset(new ConfigUtil());
        }
        mutex.unlock();
    }

    return *instance.data();
}

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()
"Verbose"
"Verbose"
~ConfigUtil()

不需要像前面那样手动调用 release(),ConfigUtil 被自动析构了。

思考

从 ConfigUtil 的实现,我们知道了怎么写一个单例类,现在需要另一个单例的类如 ConnectionPool(请自己实现,相关的功能函数可以随便返回点东西表示一下就可以了),比较一下它们的代码是否有什么相似部分,是不是单例的实现部分都要抄一遍 ConfigUtil 的相关代码?

转载:http://qtdebug.com/Singleton-2-AutoPointer.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值