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

C++ 中的 Meyer‘s Singleton

目录
  • 1. 什么是 Singleton 模式?
  • 2. 传统的 Singleton 实现及其问题
  • 3. Meyer‘s Singleton:现代而优雅的解决方案
    • 实现代码
  • 4. Meyer’s Singleton 的工作原理与关键特性
  • 5. 使用方法
  • 6. 优点
  • 7. 潜在缺点与注意事项
  • 总结
  • 全局锁(单例模式)


1. 什么是 Singleton 模式?

Singleton(单例)是一种设计模式,其核心目标是确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。

2. 传统的 Singleton 实现及其问题

在 C++11 标准之前,实现一个线程安全的 Singleton 通常比较麻烦。常见的“双重检查锁定”模式虽然有效,但代码复杂,且在不正确的内存模型下容易出错。

// 传统的双重检查锁定 (复杂且容易出错,尤其在C++11之前)
class OldSingleton {
private:static OldSingleton* instance;static std::mutex m_mutex;OldSingleton() {} // 私有构造函数public:static OldSingleton* getInstance() {if (instance == nullptr) { // 第一次检查std::lock_guard<std::mutex> lock(m_mutex);if (instance == nullptr) { // 第二次检查instance = new OldSingleton();}}return instance;}// 删除拷贝构造和赋值操作OldSingleton(const OldSingleton&) = delete;OldSingleton& operator=(const OldSingleton&) = delete;
};// 在类外初始化静态成员
OldSingleton* OldSingleton::instance = nullptr;
std::mutex OldSingleton::m_mutex;

3. Meyer‘s Singleton:现代而优雅的解决方案

Meyer’s Singleton 是由 C++ 专家 Scott Meyers 在《Effective C++》中提出的。它利用了 C++ 标准中一个非常重要的特性:局部静态变量的初始化是线程安全的

核心思想:在函数内部定义一个静态局部对象,并直接返回它。

实现代码

class MeyerSingleton {
private:// 私有构造函数,防止外部创建实例MeyerSingleton() {std::cout << "MeyerSingleton constructed!" << std::endl;}// 私有析构函数(可选,但通常建议)~MeyerSingleton() {std::cout << "MeyerSingleton destroyed!" << std::endl;}public:// 删除拷贝构造函数和赋值操作符,确保唯一性MeyerSingleton(const MeyerSingleton&) = delete;MeyerSingleton& operator=(const MeyerSingleton&) = delete;// 关键的全局访问点static MeyerSingleton& getInstance() {static MeyerSingleton instance; // 核心:局部静态变量return instance;}// 一个示例成员函数void doSomething() {std::cout << "Doing something..." << std::endl;}
};

4. Meyer’s Singleton 的工作原理与关键特性

  1. 首次调用时构造

    • 当程序第一次调用 getInstance() 时,局部静态变量 instance 会被创建。
    • 后续调用都会直接返回这个已存在的实例的引用。
  2. 线程安全

    • 根据 C++11 及以后的标准(§[stmt.decl] §4),局部静态变量的初始化是线程安全的
    • 编译器会在底层自动为我们插入必要的锁或使用更高效的线程安全初始化机制(如 std::call_once),确保 instance 只被初始化一次,即使在多线程环境下。
  3. 自动析构

    • 静态局部变量在程序结束时(main 函数退出后)会自动析构。
    • 析构的顺序与它们构造的顺序相反。这有时可能会带来问题,如果 Singleton 的析构函数依赖于另一个已经被析构的全局对象(这就是所谓的“析构顺序问题”)。

5. 使用方法

int main() {// 获取单例实例的唯一方式MeyerSingleton& singleton = MeyerSingleton::getInstance();singleton.doSomething();// 再次调用,返回的是同一个实例MeyerSingleton::getInstance().doSomething();// 错误!构造函数是私有的,无法直接创建对象// MeyerSingleton s1;// 错误!拷贝构造函数被删除// MeyerSingleton s2 = singleton;return 0;
}

6. 优点

  1. 简洁优雅:代码量极少,意图清晰。
  2. 线程安全:无需手动处理锁,由 C++ 标准保证。
  3. 按需构造:只有在第一次被使用时才会创建实例,避免了程序启动时不必要的资源开销。
  4. 自动管理生命周期:无需手动 newdelete,避免了内存泄漏的风险。

7. 潜在缺点与注意事项

  1. 析构顺序问题

    • 如果 Singleton 在析构时,其成员函数被另一个正在析构的全局对象调用,可能会导致未定义行为。对于大多数不依赖其他全局对象的 Singleton 来说,这不是问题。
  2. C++11 之前不可用

    • 这种线程安全保证是 C++11 标准才引入的。在旧的编译器中,它可能不是线程安全的。
  3. 不可控的析构时机

    • 有时你可能希望 Singleton 的生命周期贯穿整个程序,或者在特定时刻手动销毁它。Meyer‘s Singleton 的析构时机是固定的(程序结束时),无法灵活控制。

总结

Meyer’s Singleton 是当今 C++(C++11 及以后)中实现 Singleton 模式的首选方法。它以其极致的简洁性、内置的线程安全性和自动的生命周期管理,几乎完全取代了那些复杂且容易出错的传统实现。

除非你有非常特殊的生命周期管理需求,或者需要在 C++11 之前的标准下工作,否则都应该使用 Meyer‘s Singleton。


全局锁(单例模式)

#include <mutex>class GlobalLock {
public:static GlobalLock& getInstance() {static GlobalLock instance;return instance;}void lock() {mutex_.lock();}void unlock() {mutex_.unlock();}bool try_lock() {return mutex_.try_lock();}// 删除拷贝构造函数和赋值运算符GlobalLock(const GlobalLock&) = delete;GlobalLock& operator=(const GlobalLock&) = delete;private:GlobalLock() = default;~GlobalLock() = default;std::mutex mutex_;
};

使用方式

// 使用方式
GlobalLock::getInstance().lock();
// 临界区代码
GlobalLock::getInstance().unlock();// 或者使用 lock_guard
std::lock_guard<std::mutex> lock(GlobalLock::getInstance().getMutex());
http://www.jsqmd.com/news/27738/

相关文章:

  • java 比较数组数据大小
  • lua+nginx用户鉴权脚本--get方法
  • 2025 年算法备案咨询服务公司最新推荐榜,技术实力与合规能力双维度权威测评解析
  • windows系统生成当日的时间戳文件脚本
  • docker中 Created和Exited状态容器导致磁盘空间爆满的处理的方式
  • 智能感应倒液器微波雷达方案和红外方案的优势和劣势
  • 读完《代码大全2》
  • 2025 年闭式冷却塔,玻璃钢冷却塔,方形冷却塔,圆形冷却塔厂家最新推荐,实力品牌深度解析采购无忧之选!
  • 2025 年湖南冷却塔,长沙冷却塔,封闭式冷却塔,测试设备配套冷却塔厂家最新推荐,聚焦资质、案例、售后的五家机构深度解读
  • 2025年口碑好的积分球公司排名前十推荐:合肥金水木光电科技
  • 积分球公司的信赖之选:十大好评如潮的靠谱厂家排行榜
  • 在linux上使用perf火焰图
  • Windows的hyper-v虚拟机设置静态IP,使用一段时间或者宽带网络变化后,出现宝塔面板页面时好时坏,有时正常,有时无法打开问题,bt status查看宝塔状态又是正常的
  • HT-LFCG-3800+
  • 基础排序算法(六)希尔排序
  • 2025 年集装袋厂家最新推荐榜:从技术创新到品质管控,深度解析行业优质企业的综合实力与市场竞争力内拉筋 / D 型导电 / C 型导电 / D 型防静电集装袋公司推荐
  • 英语词性
  • 组织研磨仪厂家哪家好?2025年知名品牌推荐
  • openresty中使用ngx.sleep(0)防止worker进程阻塞
  • Playwright定位元素与操作
  • 2025 年最新推荐!国内 AI 教育培训机构榜单出炉,涵盖企业 AI 培训 / AI 能力提升 / AI 应用落地等多领域专业机构
  • 信息论之联合熵、边缘熵、条件熵
  • P9755 [CSP-S 2023] 种树
  • 登录后编码错误提示处理
  • 2025 升降机厂家最新推荐权威榜单!附协会测评数据与核心优势深度解析
  • 【ArcMap】修改选中路线的属性表的列名
  • 审计组件
  • vscode launch.json debug 带caffe库的工程代码
  • PADS丨出 gerber 通用教程
  • jmeter阶梯试压测