IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> C++ 单例模式 饿汉+懒汉实例 -> 正文阅读

[Java知识库]C++ 单例模式 饿汉+懒汉实例

C++单例模式及实例

单例模式是非常常用的设计模式,通俗讲就是保证全局仅存在一份类型实例。

我们通过模板类来实现泛型单例模式,所有单例类对象存储在static变量中,全局静态变量要早于main方法之前初始化,且只初始化一次,因此只要调用类似HungrySingleton<log>::GetInstance()这样的语句即可获取单例对象log的指针。

对于C++来说,需要保证单例类HungrySingletonLazySingleton构造函数、析构函数、拷贝和赋值通通不可用,因此其继承了一个删除了上述方法的父类,从而禁止二者调用。

饿汉式比较容易处理,只需要在类体外进行相应的定义即进行了初始化。由于static对象只进行一次初始化,因此饿汉式自身保证了线程安全性。

懒汉式需要考虑线程安全的问题,当真正用到时才需要进行实例化,这个实例化过程需要保证线程安全。方法是在检测到对象不存在时加锁,并再一次检测,如果真的不存在,则进行实例化。确保实例化后可以从静态对象中安全取出单例对象。

**已废弃方法:**当然,不要忘了delete,我们可以在static初始化时创建一个Garbage类,其负责在单例对象生命期结束时,回收相应资源。

2/18日修改:上述通过调用另一个静态Garbage对象来删除Instance在实测中无法调用析构函数,改为使用智能指针来正确释放

/**
 * @file singleton.h
 * @author huang (shaobohuang.1998@gmail.com)
 * @brief 简单的singleton实例
 * @version 0.1
 * @date 2022-02-17
 * 
 * @copyright Copyright (c) 2022
 * 
 */
#include <pthread.h>
#include <iostream>
#include <memory>
/**
 * @brief 不允许单例类调用构造、析构、复制和赋值,仅能通过静态方法获取实例
 * 
 */
class NonInstantiatable {
    public:
        NonInstantiatable() = delete;
        ~NonInstantiatable() = delete;
        NonInstantiatable(const NonInstantiatable&) = delete;
        NonInstantiatable& operator=(const NonInstantiatable&) = delete;
};

template<typename T>
class HungrySingleton : public NonInstantiatable{
    // 饿汉式
    public:
        static std::shared_ptr<T> GetInstance();
    private:
        static std::shared_ptr<T> Instance;

};

template<typename T>
std::shared_ptr<T> HungrySingleton<T>::Instance(new T);

template<typename T>
std::shared_ptr<T> HungrySingleton<T>::GetInstance() {
    return Instance;
}

class MutexImpl {
    public:
        MutexImpl() {
            std::cout<< "mutex created" << std::endl;
            pthread_mutex_init(&m_mutex, nullptr);
        }
        void Lock() {
            pthread_mutex_lock(&m_mutex);
        }
        void Unlock() {
            pthread_mutex_unlock(&m_mutex);
        }
        ~MutexImpl() {
            std::cout<< "mutex cleared" << std::endl;
            pthread_mutex_destroy(&m_mutex);
        }
    private:
        pthread_mutex_t m_mutex;
};

template<typename T>
class LazySingleton : public NonInstantiatable{
    // 懒汉式
    public:
        static std::shared_ptr<T> GetInstance();
    private:
        static std::shared_ptr<T> Instance;
        static std::unique_ptr<MutexImpl> Mutex;
};

template<typename T>
std::shared_ptr<T> LazySingleton<T>::Instance(nullptr);

template<typename T>
std::unique_ptr<MutexImpl> LazySingleton<T>::Mutex(new MutexImpl);

template<typename T>
std::shared_ptr<T> LazySingleton<T>::GetInstance() {
    if(!Instance) {
        Mutex->Lock();
        if(!Instance) {
            LazySingleton<T>::Instance.reset(new T);
        }
        Mutex->Unlock();
    }
    return Instance;
}

template<typename T>
class Singleton : public NonInstantiatable{
    // 基于局部静态对象的懒汉式
    public:
        static T* GetInstance() {
            static T v;
            return &v;
        }
};
/**
 * @file singleton_main.cc
 * @author your name (you@domain.com)
 * @brief main方法
 * @version 0.1
 * @date 2022-02-17
 * 
 * @copyright Copyright (c) 2022
 * 
 */

/**
 * @file singleton_main.cc
 * @author your name (you@domain.com)
 * @brief main方法
 * @version 0.1
 * @date 2022-02-17
 * 
 * @copyright Copyright (c) 2022
 * 
 */
#define NUM 20

#include "singleton.h"
#include <iostream>

#include <unistd.h>       // for syscall()
#include <sys/syscall.h>  // for SYS_xxx definitions
 
class Log {
    public:
        Log() {
            std::cout << "Log Initialed" << std::endl;
        }
        ~Log() {
            std::cout << "Log cleared" << std::endl;
        }
};

void* test(void* data) {
    auto log = HungrySingleton<Log>::GetInstance();
    std::cout << "pthread:" << syscall(SYS_gettid) << "log address" << log.get() << std::endl;
    return NULL;
}

int main(int argc, char** argv) {
    //auto log1 = HungrySingleton<Log>::GetInstance();
    //auto log2 = HungrySingleton<Log>::GetInstance();
    //auto log1 = LazySingleton<Log>::GetInstance();
    //auto log2 = LazySingleton<Log>::GetInstance();
    /*if(log1 == log2) {
        std::cout << "equal" << std::endl;
    }*/
    pthread_t t[NUM];
    for(int i = 0; i < NUM; ++i) {
        pthread_create(&t[0] + i, 0, test, NULL);
    }
    for(int i = 0; i < NUM; ++i) {
        pthread_join(t[i], NULL);
    }
    return 0;
}
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-02-19 01:00:55  更:2022-02-19 01:03:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:48:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码