当前位置: 首页 > article >正文

c++懒汉式单例模式(Singleton)多种实现方式及最优比较

前言

关于C++懒汉式单例模式的写法,大家都很熟悉。早期的设计模式中有代码示例。比如:

class Singleton {
    private: static Singleton *instance;

    public: static Singleton *getInstance() {
        if (NULL == instance)
            instance = new Singleton();

        return instance;
    }
};

它的缺点:线程不安全,指针资源没有释放。

自从C++11推出后,单例模式有了更优秀的写法,下面来介绍下。

使用 std::call_once 实现

#include <iostream>
#include <mutex>
#include <memory>
 
class Singleton {
private:
    Singleton() { std::cout << "Singleton constructed." << std::endl; }
    
    static std::once_flag initInstanceFlag;
    static std::unique_ptr<Singleton> instance;
 
    // 删除拷贝构造函数和赋值操作符
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
 
public:
    static Singleton& getInstance() {
        std::call_once(initInstanceFlag, []() {
            instance.reset(new Singleton());
        });
        return *instance;
    }
 
    void someMethod() {
        std::cout << "Method of the singleton" << std::endl;
    }
 
    ~Singleton() {
        std::cout << "Singleton destructed." << std::endl;
    }
};
 
std::once_flag Singleton::initInstanceFlag;
std::unique_ptr<Singleton> Singleton::instance;
 
// 使用示例
void threadFunction() {
    Singleton& singleton = Singleton::getInstance();
    singleton.someMethod();
}
 
int main() {
    std::thread t1(threadFunction);
    std::thread t2(threadFunction);
 
    t1.join();
    t2.join();
 
    return 0;
}

优点:线程安全、内存安全。显式控制初始化过程,适合需要延迟初始化的场景。

使用局部静态变量实现(C++11及以后)

#include <iostream>
#include <memory>
 
class Singleton {
private:
    Singleton() { std::cout << "Singleton constructed." << std::endl; }
 
    // 关闭拷贝构造函数、右值拷贝构造函数和赋值操作符
    Singleton(const Singleton&) = delete;
    Singleton(const Singleton &&) = delete;
    Singleton& operator=(const Singleton&) = delete;
 
public:
    static Singleton& getInstance() {
        static Singleton instance;
        return instance;
    }
 
    void someMethod() {
        std::cout << "Method of the singleton" << std::endl;
    }
 
    ~Singleton() {
        std::cout << "Singleton destructed." << std::endl;
    }
};
 
// 使用示例
void threadFunction() {
    Singleton& singleton = Singleton::getInstance();
    singleton.someMethod();
}
 
int main() {
    std::thread t1(threadFunction);
    std::thread t2(threadFunction);
 
    t1.join();
    t2.join();
 
    return 0;
}

优点:线程安全。代码最简洁,由C++11标准保证线程安全,适合大多数场景。
缺点:适用于不复杂的工程。因为如果静态类之间有依赖,可能会导致C++的一些未定义的行为。

Meyers 的版本

Scott Meyers 是 Effective C++系列的作者,他最早提供了简洁版本的 Singletion 模型。根据他提供的模型,可以写出线程安全又简单的单例模式。代码如下:

#include <stdio.h>

class singleton {
  static singleton &instance() {
    static singleton instance;
    return instance;
  } // instance

  singleton(const singleton &) = delete;
  singleton & operator = (const singleton &) = delete;

private:
  singleton() {}
  ~singleton() {}

public:
  void out(){ printf("out\n"); }
}; // struct singleton

int main() {
    singleton::instance().out();
    return 0;
}

缺点:单一的实例总是在 main() 开始之前被初始化的,该实现无法做到 lazyinit。
优化版本:

 template<typename T>
 class singleton {
 public:
	 static T &instance();
	
	 singleton(const singleton &) = delete;
	 singleton &operator=(const singleton) = delete;
	
 protected:
	 singleton() = default;
 };

 template<typename T>
 inline T &singleton<T>::instance() {
   static const std::unique_ptr<T> instance{new T{token{}}};
   return *instance;
 }

优点:线程安全、内存安全。

鸿蒙单例实现

线程安全、内存安全、双重检测、延迟加载、支持lazyinit、实现懒汉式单例模板。当前在商业(鸿蒙手机操作系统)使用中,代码可靠。
使用说明,请点这里。
下面只展示DelayedSingleton实现示例。完整代码以及其它几种单例实现,请点这里。
补充说明:对于懒汉式单例模式双重检测,有的人嫌代码麻烦,将构造函数私有化来实现。这个大家自己去评价。其实也没几行代码。写上双重检测,逻辑上也是提醒大家代码实现的风险点。不算优化问题。论可靠,还是相信鸿蒙吧。

template<typename T>
class DelayedSingleton : public NoCopyable {
public:
    static std::shared_ptr<T> GetInstance();
    static void DestroyInstance();

private:
    static std::shared_ptr<T> instance_;  instance.
    static std::mutex mutex_; 
};

template<typename T>
std::shared_ptr<T> DelayedSingleton<T>::instance_ = nullptr;

template<typename T>
std::mutex DelayedSingleton<T>::mutex_;

template<typename T>
std::shared_ptr<T> DelayedSingleton<T>::GetInstance()
{
    if (instance_ == nullptr) {
        std::lock_guard<std::mutex> lock(mutex_);
        if (instance_ == nullptr) {
            std::shared_ptr<T> temp(new (std::nothrow) T);
            instance_ = temp;
        }
    }

    return instance_;
}

template<typename T>
void DelayedSingleton<T>::DestroyInstance()
{
    std::lock_guard<std::mutex> lock(mutex_);
    if (instance_ != nullptr) {
        instance_.reset();
        instance_ = nullptr;
    }
}

http://www.kler.cn/news/288671.html

相关文章:

  • laravel8快速开发简单博客系统(二)
  • HarmonyOS NEXT实战:“相机分段式拍照”性能提升实践
  • 深度学习100问11:什么是one-hot编码
  • Anaconda安装和环境配置教程(深度学习准备)
  • 用SQL语句 对时间进行周期计算week(date,mode)
  • SAP B1 三大基本表单标准功能介绍-物料主数据(下)
  • ClickHouse实时探索与实践 京东云
  • 使用LLaMA-Factory快速训练自己的专用大模型
  • 空间计量 | 似不相关回归SUR
  • k8s的Service和持久化存储
  • B端系统门门清之:CRM-客户管理系统,客户是一切的源头。
  • 动态规划---分割等和子集
  • 8.30-使用docker容器部署考试项目+使用Dockerfile部署java项目
  • 视频:Python深度学习量化交易策略、股价预测:LSTM、GRU深度门控循环神经网络|附代码数据...
  • (十五)SpringCloudAlibaba-Sentinel持久化到Nacos
  • python图像处理基础(skimage、PIL、OpenCV)
  • Java设计模式之建造者模式详细讲解和案例示范
  • JVM面试(二)内存区域划分
  • 无人机专业大学生参与无人机飞手执照培训技术分析
  • 【CPP 基础】如何把cpp库,分装给 c# 用。
  • 数据结构---线性表--栈和队列
  • ActiveMQ实战指南:实现发布/订阅(publish-subscribe)消息发送!
  • Unity Android 进阶之 【Android 添加一个启动动画】在Unity场景加载完之前,避免 【Unity 启动界面慢 黑屏时间长】的情况
  • 青远生态为云南林业规划院定制开发的自然保护地规划智能编制系统顺利通过验收
  • Golang | Leetcode Golang题解之第385题迷你语法分析器
  • Java图形用户界面之Applet设计
  • python django 使用教程
  • 使用 streamlink 把 m3u8 转为 mp4
  • 代码随想录 刷题记录-24 图论 (1)理论基础 、深搜与广搜
  • 保姆级Maven安装、配置、版本查询教程(包含配置本地仓库、阿里云私服、环境变量)