C++的懒汉式单例模式和magic static单例模式

最近要公司开发一个机器人分布式调度器,刚刚毕业的我瑟瑟发抖,准备用单例模式向机器人提供调度算法接口,赶紧补习下知识。

什么是单例模式

单例模式是一种常用的设计模式,主要指在程序运行过程中,一个类有且仅有一个实例,并且向外提供获取该实例的接口。实现单例模式有三个要点:类只能有一个实例;类自行创建这个实例;类自行向整个系统提供这个实例。

简单的懒汉式实现

最简单的懒汉式实现单例模式:

class Singleton
{
private:
    Singleton() { std::cout << "Constructor!" << std::endl; };
    Singleton(Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    //私有化赋值构造函数和拷贝构造函数,避免通过这两种方式有其他实例
    static Singleton* instancePtr;
    //类的静态局部变量只有一个,作为实例的指针
public:
    ~Singleton() { std::cout << "Destructor!" << std::endl; };
    static Singleton* instance()//静态函数只有一个
    {
        if(instancePtr == nullptr)
            instancePtr = new Singleton;
        return instancePtr;
    }
    void Fun() { std::cout << "Fun" << std::endl; };//其他公有接口
};

存在的问题:

  1. 线程不安全:如果第一个线程在if中判断为空,同时另一个线程也进入if判断,那么new将会调用两次。解决方法:加锁
  2. 内存泄漏:在这个例子中只使用了new但是没有delete对象,这会导致内存泄露。解决方法:智能指针如shared_ptr

懒汉式改进

考虑到线程安全和内存安全对上例进行改进:

#include <iostream>
#include <memory>
#include <mutex>

class Singleton
{
private:
    Singleton() { std::cout << "Constructor!" << std::endl; };
    Singleton(Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    static std::shared_ptr<Singleton> instancePtr;
    static std::mutex sMutex;
    //改用共享指针和互斥量
public:
    ~Singleton() { std::cout << "Destructor!" << std::endl; };
    static std::shared_ptr<Singleton> instance()
    {
        if(instancePtr == nullptr)
        {
            std::lock_guard<std::mutex> sLock(sMutex);//当实例未创建时需要加锁,lock_guard在构造时加锁,析构时自动释放
            if(instancePtr == nullptr)
            {
                instancePtr = std::make_shared<Singleton>();
            }
        }
        return instancePtr;
    }
    void Fun() { std::cout << "Fun" << std::endl; };//其他公有接口
};

经典懒汉式magic static

这个写法来自于《Effective C++》系列的作者Meyers,不得不说这个系列的书很经典,我最近每天上班前都要看几个条款。具体写法如下:

#include <iostream>

class Singleton
{
private:
    Singleton() { std::cout << "Constructor!" << std::endl; };
    Singleton(Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
public:
    ~Singleton() { std::cout << "Destructor!" << std::endl; };
    static Singleton& instance()
    {
        static Singleton ins;//静态局部变量,内存中只有一个,且只会被初始化一次
        return ins;
    }
    void Fun() { std::cout << "Fun" << std::endl; };//其他公有接口
};

为什么这么简洁的代码能够避免单例模式的各种问题?

If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.
如果当变量在初始化的时候,并发同时进入声明语句,并发线程将会阻塞等待初始化结束。

简单来说就是当多个线程同时调用instance接口时,如果ins实例尚未创建,那么就会进入初始化,同时阻塞其他线程初始化该实例,从而保证线程安全,同时由于变量保存在全局静态区,也能够保证内存安全。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是懒汉单例模式和饿汉单例模式的异同: 相同点: 1. 都是单例模式,即保证一个类只有一个实例对象。 2. 都使用了私有的构造函数,防止外部创建实例对象。 3. 都使用了静态变量来保存实例对象。 不同点: 1. 创建对象的时机不同:饿汉在类加载时就创建了对象实例,而懒汉是在使用时才创建。 2. 线程安全性不同:饿汉天生是线程安全的,因为在类加载时就已经创建了对象实例,而懒汉需要考虑线程安全问题,可以使用synchronized关键字或者双重检查锁定等方来保证线程安全。 3. 性能不同:饿汉在类加载时就创建了对象实例,所以在访问速度和反应时间上都比懒汉快,但是如果这个实例一直没有被使用,那么就会造成内存浪费。而懒汉只有在使用时才会创建对象实例,所以在内存占用上比饿汉要低,但是在访问速度和反应时间上会稍微慢一些。 下面是懒汉单例模式的示例代码: ```python class Singleton: __instance = None def __init__(self): if Singleton.__instance != None: raise Exception("该类已经实例化过了") else: Singleton.__instance = self @staticmethod def getInstance(): if Singleton.__instance == None: Singleton() return Singleton.__instance ``` 下面是饿汉单例模式的示例代码: ```python class Singleton: __instance = Singleton() def __init__(self): if Singleton.__instance != None: raise Exception("该类已经实例化过了") else: Singleton.__instance = self @staticmethod def getInstance(): return Singleton.__instance ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值