进步始于交流
收获源于分享

C++设计模式-单例模式

介绍

几个重点:

  • 构造函数为private
  • 提供一个获取单例对象指针的函数
  • 一个静态指针成员存储单例对象

注意:

  • 获取单例对象也可以获取对象引用,但要注意拷贝构造函数和赋值运算符
  • 如果有多线程访问单例,需要注意线程同步

范例

源码GitHub:CppDesignPattern

单线程

#ifndef SIGLETON_H
#define SIGLETON_H
/**
 * @brief 非线程安全单例,无多线程时使用
 */
class Singleton {
public:
    /**
     * @brief 单例模式,获取实例化对象
     * @param 无
     * @return 单例对象
     */
    static Singleton *GetInstance();
    /**
     * @brief 单例模式,主动销毁实例化对象
     * @param 无
     * @return 无
     */
    static void DestoryInstance();
private:
    /**
     * @brief 构造函数
     */
    Singleton();
    /**
     * @brief 单例模式在程序结束时自动删除单例的方法
     */
    class SingletonDel {
    public:
        ~SingletonDel() {
            if (m_instance != nullptr) {
                delete m_instance;
                m_instance = nullptr;
            }
        }
    };
    static SingletonDel m_singleton_del;///程序结束时销毁
    static Singleton *m_instance;       //单例对象指针
};
#endif // SIGLETON_H
//cpp
#include "sigleton.h"
Singleton* Singleton::m_instance = nullptr;
Singleton *Singleton::GetInstance() {
    if (m_instance == nullptr) {
        m_instance = new Singleton();
    }
    return m_instance;
}

void Singleton::DestoryInstance() {
    if (m_instance != nullptr) {
        delete m_instance;
        m_instance = nullptr;
    }
}

Singleton::Singleton() {
}

多线程

#ifndef THREAD_SAFE_SINGLETON_H
#define THREAD_SAFE_SINGLETON_H
/**
 * @brief 线程安全单例,多线程时使用
 */
class ThreadSafeSingleton {
public:
    /**
     * @brief 单例模式,获取实例化对象
     * @param 无
     * @return 单例对象
     */
    static ThreadSafeSingleton* GetInstance();
    /**
     * @brief 单例模式,主动销毁实例化对象
     * @param 无
     * @return 无
     */
    static void DestoryInstance();
private:
    /**
     * @brief 构造函数
     */
    ThreadSafeSingleton();
    /**
     * @brief 单例模式在程序结束时自动删除单例的方法
     */
    class SingletonDel {
    public:
        ~SingletonDel() {
            if (m_instance != nullptr) {
                delete m_instance;
                m_instance = nullptr;
            }
        }
    };
    static ThreadSafeSingleton m_singleton_del;///程序结束时销毁
    static ThreadSafeSingleton *m_instance;       //单例对象指针
};
#endif // THREAD_SAFE_SINGLETON_H

#include "thread_safe_singleton.h"
#include <QMutex>
#include <QMutexLocker>
namespace thread_safe_singleton_private {
    static QMutex mutex;
}
ThreadSafeSingleton* ThreadSafeSingleton::m_instance = nullptr;
ThreadSafeSingleton *ThreadSafeSingleton::GetInstance() {
    if (m_instance == nullptr) {
        QMutexLocker lock(&thread_safe_singleton_private::mutex);
        if (m_instance == nullptr) {
            m_instance = new ThreadSafeSingleton();
        }
    }
    return m_instance;
}

void ThreadSafeSingleton::DestoryInstance() {
    if (m_instance != nullptr) {
        delete m_instance;
        m_instance = nullptr;
    }
}

ThreadSafeSingleton::ThreadSafeSingleton() {
}

上面的范例提供了主动销毁单例的方法同时提供了自动销毁的方法。

若主动销毁需注意其他存储了单例指针的对象

C++11单例模式实现

C++11保证静态成员构造的时候线程安全,所以可以避免在构造时通过线程锁的方式实现线程安全

#ifndef CPP11_SIGLETON_H
#define CPP11_SIGLETON_H
#include <QDebug>
//C++11的单例实现
//c++11自动处理静态成员初始化竞争,是线程安全的
template <typename T>
class Cpp11Sigleton {
public:
    static T *GetInstance() {
        static T instance;
        return &instance;
    }
};
class TestCpp11Sigleton {
    friend class Cpp11Sigleton<TestCpp11Sigleton>;
private:
    TestCpp11Sigleton(){qDebug()<<"created"<<this;}
};
#endif // CPP11_SIGLETON_H

通过一个通用的单例模板类,并在需要单例类中将构造函数私有化,设置与模板类的friend关系即可实现多线程单例创建的安全。

注意返回的仍然是函数指针,若返回引用请注意拷贝和复制方法的处理

  • Class(const Class&); 拷贝
  • Class&operator=(const Class&); 复制

测试:

#include <cpp11_sigleton.h>
#include <thread>
int main(int argc, char *argv[]) {
    std::thread t1(Cpp11Sigleton<TestCpp11Sigleton>::GetInstance);
    t1.detach();
    std::thread t2(Cpp11Sigleton<TestCpp11Sigleton>::GetInstance);
    t2.detach();
    std::thread t3(Cpp11Sigleton<TestCpp11Sigleton>::GetInstance);
    t3.detach();
    std::thread t4(Cpp11Sigleton<TestCpp11Sigleton>::GetInstance);
    t4.detach();
    Cpp11Sigleton<TestCpp11Sigleton>::GetInstance();
    Cpp11Sigleton<TestCpp11Sigleton>::GetInstance();
    Cpp11Sigleton<TestCpp11Sigleton>::GetInstance();
    Cpp11Sigleton<TestCpp11Sigleton>::GetInstance();
}

只会输出一次构造函数的qDebug()<<“created”<<this;

C++11单例模式实现构造时参数传入

11支持可变模板参数,所以可以用一个模板实现不同类型参数的构造,GetInstance方法改一下:

template<typename... Args>
static T* GetInstance(Args&&... args) {
    static T instance(std::forward<Args>(args)...);
    return &m_pInstance;
}

相关链接:C++设计模式

赞(1) 打赏
未经允许不得转载:Coologic » C++设计模式-单例模式

评论 2

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. #0

    请问一下这里的&lt;QMutex&gt;是怎样调用的?
    是直接在qt里面编程的?
    还是讲QMutex等头文件和库文件分离出来使用?

    灰烟飞5年前 (2018-07-02)回复
    • #include QMutex

      Techie亮5年前 (2018-11-10)回复

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏