C++ 单例模式 饿汉+懒汉实例

C++单例模式及实例

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

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

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

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

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

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

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

9/20:在字节实习几个月后来后在看看自己写的什么狗屁代码…静态变量本身是一种特殊变量,由编译器在进入main之前创建和初始化,在离开main之后由编译器释放,所以何必用智能指针包装…其实公司项目中最常用局部变量的那种单例,编译器保证了局部变量的初始化时是线程安全的

/**
 * @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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值