C++实现单例模式

单例模式的实现方式

📌想要实现一个单例设计模式,必须遵循以下规则:

  • 私有的构造函数:防止外部代码直接创建类的实例
  • 私有的静态实例变量:保存该类的唯一实例
  • 公有的静态方法:通过公有的静态方法来获取类的实例

而在 C++ 中,推荐 静态局部变量的懒汉单例,简单且线程安全 (不需要锁、不需要静态实例变量):

class Single {
public:
    static Single& GetInstance();  // 公有的静态函数,用于获取类的实例
private:
    Single() = default;  // 私有的构造函数,使用默认构造函数作为实现
};

Single& Single::GetInstance() {
    static Single single;  // 静态实例变量,保存该类的唯一实例
    return single;
}

更加完整的版本(禁止外部拷贝构造和赋值操作):

class Single {
public:
    static Single& GetInstance();  // 公有的静态函数,用于获取类的实例
private:
    Single() = default;  // 私有的构造函数,使用默认构造函数作为实现
    ~Single() = default;
	Single(const Single &single) = delete;  // 禁止外部拷贝构造
	const Single &operator=(const Single &single) = delete;  // 禁止外部赋值操作
};

Single& Single::GetInstance() {
    static Single single;  // 静态实例变量,保存该类的唯一实例
    return single;
}

📌注意点:

  1. GetInstance 应当返回实例的引用,否则将产生副本
  2. 上面的实现中,没有使用私有的静态实例变量,而是利用了 C++ static 关键字,局部的 static Single single 的生命周期和程序运行周期相同
  3. 这是懒汉模式,因为只在第一次调用 GetInstance 时才会创建对象。
  4. 这种实现方式是线程安全的,参考 C++ 标准(§6.7 [stmt.dcl] p4):如果有多个线程同时进入变量的声明部分,也就是说,多个线程同时试图访问并初始化这个变量,那么当这个变量正在被初始化时,所有同时进入的线程会等待变量的初始化完成

§6.7 [stmt.dcl] p4
If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.

单例模式练习

📚练习题:【设计模式专题之单例模式】1.小明的购物车 (kamacoder.com)

解答:

#include <iostream>
#include <string>
#include <sstream>
#include <map>
#include <vector>
using namespace std;

class Cart {
public:
    static Cart& GetInstance();  // 公有的静态函数,用于获取类的实例
    void addToCart(string name, int count);
    void printCart();
private:
    Cart() = default;  // 私有的构造函数,使用默认构造函数作为实现
    ~Cart() = default;
    Cart(const Cart &cart) = delete;  // 禁止外部拷贝构造
    const Cart &operator=(const Cart &cart) = delete;  // 禁止外部赋值操作
    vector<string> order;  // 题目要求输出顺序与输入顺序相同,所以加一个order来记录
    map<string, int> mp;
};

Cart& Cart::GetInstance() {
    static Cart cart;  // 静态实例变量,保存该类的唯一实例
    return cart;
}

void Cart::addToCart(string name, int count) {
    if (mp.find(name) != mp.end()) {
        mp[name] += count;
    } else {
        order.push_back(name);
        mp[name] = count;
    }
}

void Cart::printCart() {
    for (const string& name : order) {
        cout << name << " " << mp[name] << endl;
    }
}

int main() {
    while(1) {
        string input;
        getline(cin, input);
        if (input.empty()) break;  // 空输入,跳出循环
        stringstream ss(input);
        string name;
        int n;
        ss >> name >> n;
        Cart::GetInstance().addToCart(name, n);
    }
    Cart::GetInstance().printCart();
    return 0;
}

参考

  1. stackoverflow-静态局部变量的懒汉单例
  2. CSDN-C++ 单例模式总结(5种单例实现方法)
  3. 代码随想录-单例模式练习
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值