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();
相关推荐
IT小白架构师之路9 小时前
常用设计模式系列(十八)-责任链模式
设计模式·责任链模式
R-G-B10 小时前
【15】OpenCV C++实战篇——fitEllipse椭圆拟合、 Ellipse()画椭圆
c++·人工智能·opencv·fitellipse椭圆拟合·ellipse画椭圆·椭圆拟合·绘制椭圆
界面开发小八哥12 小时前
MFC扩展库BCGControlBar Pro v36.2:MSAA和CodedUI测试升级
c++·mfc·bcg·界面控件
极客BIM工作室15 小时前
C++ 限制类对象数量的技巧与实践
开发语言·javascript·c++
郝学胜-神的一滴16 小时前
Horse3D引擎研发笔记(四):在QtOpenGL下仿three.js,封装EBO绘制四边形
c++·3d·unity·游戏引擎·godot·图形渲染·虚幻
终焉代码17 小时前
【C++】STL二叉搜索树——map与set容器的基础结构
开发语言·数据结构·c++
源代码•宸17 小时前
深入浅出设计模式——行为型模式之观察者模式 Observer
开发语言·c++·经验分享·观察者模式·设计模式·raii
小马敲马18 小时前
[4.2-2] NCCL新版本的register如何实现的?
开发语言·c++·人工智能·算法·性能优化·nccl
soilovedogs19 小时前
百度之星2024初赛第二场 BD202411染色
c++·算法·百度之星
快起来别睡了19 小时前
前端设计模式:让代码更优雅的“万能钥匙”
前端·设计模式