单例模式

单例模式

介绍

单例模式理解起来比较简单, 就是一个类 它只允许创建一个对象或者实例, 那这个类就是单例类.

用处

在业务上, 有些数据只需要保存一份, 比如系统信息, 配置信息

  1. 可以节省空间、资源
  2. 方便控制, 避免多对象引起复杂操作

单例有下面两种经典的实现方式。

饿汉式 (线程安全)

它在程序启动时立即创建单例对象,而不是在首次访问时才创建。

这确保了线程安全,因为在多线程环境下,单例对象已经在程序启动阶段被创建,不需要考虑竞态条件。

使用普通静态变量方式

class HungryManSingleton {
public:
    static HungryManSingleton& getInstance() {
        // 静态成员变量确保只有一个实例
        static HungryManSingleton instance;
        return instance;
    }
    ~HungryManSingleton() {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
    // 其他成员函数和数据成员

private:
    // 私有构造函数,防止外部实例化
    HungryManSingleton() {
        // 初始化单例对象
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
    // 禁用拷贝构造函数
    HungryManSingleton(const HungryManSingleton&) = delete;
    
    // 禁用赋值操作符
    HungryManSingleton& operator=(const HungryManSingleton&) = delete;
};

使用c++11 std::call_one 方式, 是 C++ 标准库提供的一个多线程同步工具,用于确保某个函数只会在多线程环境下执行一次。通常,它与 std::once_flag 一起使用

class HungryManCallOneSingleton {
public:
  static std::shared_ptr<HungryManCallOneSingleton> getInstance() ;

  ~HungryManCallOneSingleton() {
      std::cout << __PRETTY_FUNCTION__ << std::endl;
  }
private:
    
  HungryManCallOneSingleton() {
      std::cout << __PRETTY_FUNCTION__ << std::endl;
  }
    // 禁用拷贝构造函数
  HungryManCallOneSingleton(const HungryManCallOneSingleton&) = delete;
  
  // 禁用赋值操作符
  HungryManCallOneSingleton& operator=(const HungryManCallOneSingleton&) = delete;
  
};

static std::shared_ptr<HungryManCallOneSingleton> singleton = nullptr;
static std::once_flag singletonFlag;

std::shared_ptr<HungryManCallOneSingleton> HungryManCallOneSingleton::getInstance() {
  std::call_once(singletonFlag, [&] {
    singleton = std::shared_ptr<HungryManCallOneSingleton>(new HungryManCallOneSingleton());
  });
  return singleton;
}

懒汉式

普通懒汉式单例(线程不安全)

使用互斥锁保证线程安全 (线程安全)

class LazyManSingleton {
 public:
  static std::shared_ptr<LazyManSingleton> getInstance();

  // 禁用拷贝构造函数
  LazyManSingleton(const LazyManSingleton&) = delete;

  // 禁用赋值操作符
  LazyManSingleton& operator=(const LazyManSingleton&) = delete;

  ~LazyManSingleton() { std::cout << __PRETTY_FUNCTION__ << std::endl; }

 private:
  LazyManSingleton() { std::cout << __PRETTY_FUNCTION__ << std::endl; }

  static std::shared_ptr<LazyManSingleton> instance;
  static std::mutex mutex;
};

std::shared_ptr<LazyManSingleton> LazyManSingleton::instance = nullptr;
std::mutex LazyManSingleton::mutex;
std::shared_ptr<LazyManSingleton> LazyManSingleton::getInstance() {
  // 使用互斥锁确保线程安全
  std::lock_guard<std::mutex> lock(mutex);

  if (!instance) {
    instance = std::shared_ptr<LazyManSingleton>(new LazyManSingleton());
  }
  return instance;
}

静态局部变量 (线程安全)

class StaticLazyManSingleton {
public:
    static StaticLazyManSingleton& getInstance() {
        static StaticLazyManSingleton instance; // 静态局部变量确保线程安全且延迟加载
        return instance;
    }

    // 禁用拷贝构造函数
    StaticLazyManSingleton(const StaticLazyManSingleton&) = delete;

    // 禁用赋值操作符
    StaticLazyManSingleton& operator=(const StaticLazyManSingleton&) = delete;

private:
    StaticLazyManSingleton() {
        std::cout << __PRETTY_FUNCTION__  << std::endl;
    }

    ~StaticLazyManSingleton() {
        std::cout << __PRETTY_FUNCTION__  << std::endl;
    }
};

在C++11及更高版本中,使用静态局部变量来实现单例模式通常是线程安全的,这是因为C++11引入了线程安全的静态局部变量初始化机制。这种机制确保了只有一个线程能够初始化静态局部变量,避免了竞态条件

特点

  • 构造函数为私有类型,目的是禁止外部构造。
  • 拷贝构造函数和赋值构造函数是私有类型,目的是禁止外部拷贝和赋值,确保实例的唯一性。
  • 类中有一个获取实例的静态方法,可以全局访问。

代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值