C++设计模式:单例模式 (现代C++主流实现方式Meyer‘s Singleton + 使用CRTP模板化)

文章目录

  • 单例模式
  • 创建单例类
  • 饿汉式or懒汉式
  • [现代C++单例模式的主流实现方式------Meyer's Singleton](#现代C++单例模式的主流实现方式——Meyer's Singleton)
  • [使用 CRTP 模板化单例类](#使用 CRTP 模板化单例类)

单例模式

单例模式是指程序中只需要一个实例化对象,在全局作用域或整个代码架构中,此对象只被实例化一次,就可以达到在整个程序生命周期中被使用的目的。假如程序中设计了单例模式类,但是在程序设计中实例化了多个对象,那么这些对象也只占用同一块地址空间,在代码中可以通过"%p"输出的内存地址看出,这些对象是唯一的实例。

创建单例类

如何保证类的实例有且仅有一个?

涉及一个类多对象操作的函数有以下几个:

  • 构造函数:创建一个新的对象
  • 拷贝构造函数:根据已有对象拷贝出一个新的对象
  • 拷贝赋值操作符重载函数:两个对象之间的赋值

为了把一个类可以实例化多个对象的路堵死,可以做如下处理:

  • 构造函数私有化,在类内部只调用一次,这个是可控的。
    • 由于使用者在类外部不能使用构造函数,所以在类内部创建的这个唯一的对象必须是静态的,这样就可以通过类名来访问了,为了不破坏类的封装,我们都会把这个静态对象的访问权限设置为私有的。
      在类中只有它的静态成员函数才能访问其静态成员变量,所以可以给这个单例类提供一个静态函数用于得到这个静态的单例对象。
  • 拷贝构造函数私有化或者禁用(使用 = delete)
  • 拷贝赋值操作符重载函数私有化或者禁用(从单例的语义上讲这个函数已经毫无意义,所以在类中不再提供这样一个函数,故将它也一并处理一下。)
cpp 复制代码
// 定义一个单例模式的类
class Singleton
{
public:
    Singleton(const Singleton& obj) = delete;
    Singleton& operator=(const Singleton& obj) = delete;
    static Singleton* GetInstance()
    {
        return instance;
    }
private:
    Singleton() = default;
    static Singleton* instance;
};

//静态成员变量只能在类外部初始化
Singleton* Singleton::instance = new Singleton();

饿汉式or懒汉式

饿汉模式 就是在类加载的时候立刻进行实例化,这样就得到了一个唯一的可用对象。

适用于内存大的场景,多线程调用没有线程安全问题。

懒汉模式 是在类加载的时候不去创建这个唯一的实例,而是在需要使用的时候再进行实例化。

适用于内存紧张的场景,多线程调用有线程安全问题。

参考文章:https://subingwen.cn/design-patterns/singleton/

现代C++单例模式的主流实现方式------Meyer's Singleton

Meyer's Singleton是典型的懒汉模式:

  • 线程安全(C++11 起):局部静态变量的初始化是线程安全的(编译器会自动加锁)。
  • 延迟初始化(Lazy Initialization):只有当 GetInstance() 第一次被调用时才会构造对象。
  • 自动资源管理:程序结束时,静态变量会自动析构(除非你使用了动态分配)。
  • 高效无拷贝:返回的是引用,不会产生拷贝,效率高。
cpp 复制代码
class Singleton
{
public:
    Singleton(const Singleton& obj) = delete;
    Singleton& operator=(const Singleton& obj) = delete;
    static Singleton& GetInstance()
    {
    	static Singleton instance;
        return instance;
    }
private:
    Singleton() = default;
    ~Singleton() = default;
};

使用 CRTP 模板化单例类

CRTP(Curiously Recurring Template Pattern)奇异递归模板模式 是C++中的一个编程技巧,它允许基类使用派生类的类型信息。这种模式在静态多态、计数器等场景中有应用,例如在LLVM项目中被广泛使用。通过CRTP,可以避免虚函数调用的开销,提供更高效和灵活的代码设计。
CRTP的特性表现为:

  • 基类是一个模板类
  • 派生类继承该基类时,将派生类自身作为模板参数传递给基类

实现一个 模板化的单例类,并使用 CRTP来让任意类轻松成为单例,可以这样写:

cpp 复制代码
template<typename T>
class Singleton
{
protected:
    Singleton() = default;
    ~Singleton() = default;

public:
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    Singleton(Singleton&&) = delete;
    Singleton& operator=(Singleton&&) = delete;

    static T& GetInstance()
    {
        static T instance;
        return instance;
    }
};

template<typename T> T& g = Singleton<T>::GetInstance();

使用方式

cpp 复制代码
class MyClass : public Singleton<MyClass>
{
    friend class Singleton<MyClass>; // 保证 GetInstance 可以访问构造函数
private:
    MyClass() { /* 构造逻辑 */ }
public:
    void DoSomething() { /* ... */ }
};

// 使用
MyClass::GetInstance().DoSomething();
// 或
g<MyClass>.DoSomething();
相关推荐
buhuizhiyuci35 分钟前
【QT-百日筑基篇】修真世界摸爬滚打多年,终于黄天不负有心人,突破炼器中期——常用控件QWight的属性
开发语言·c++·qt·gui·图形化
_Narcissus_4 小时前
动态规划初探(含完整代码实现)
c语言·数据结构·c++·算法·动态规划·背包问题·最短路径
法哥20125 小时前
用 C++ 控制 CMW100,到底在干什么?
开发语言·c++
AI人工智能+电脑小能手6 小时前
大白话说Java设计模式-28-模板方法模式(业务实战篇)
java·设计模式·模板方法模式·spring源码·订单系统·代码复用
_Narcissus_6 小时前
枚举和模拟算法笔记
c语言·数据结构·c++·笔记·算法·模拟·枚举
冻柠檬飞冰走茶6 小时前
《数据结构实验指导-C++语言版》 在顺序表 list 中查找元素 x
开发语言·数据结构·c++·算法·list
Brilliantwxx6 小时前
【C++】 高阶数据结构图(1)并查集
开发语言·数据结构·c++
小鱼仙官6 小时前
Ubuntu C++ NTP校时程序
linux·c++·ubuntu
冻柠檬飞冰走茶7 小时前
《数据结构实验指导-C++语言版》 返回单链表 list 中第 i 个元素值
开发语言·数据结构·c++·算法·list
老当益壮梁奶奶7 小时前
Linux软件编程学习笔记(二)Linux文件IO编程入门:从fopen到fgetc
linux·c语言·c++·笔记·学习