C++单例模式

class Node
{
public:
    //禁止拷贝和赋值
    Node(const Node&) = delete;
    Node& operator=(const Node&) = delete;
    //获取唯一实例的静态方法
    static Node& getInstance()
    {
        static Node instance;//第一次调用时初始化,线程安全C++11起
        return instance;
    }
    int a = 10086;
private:
    Node() { a = 10086; }//私有构造函数
    ~Node() = default;// 析构函数可私有,但通常不必须
};

使用

 Node& node = Node::getInstance();
 node.a = 42;

C++ 中经典的 Meyers' Singleton(迈耶斯单例)写法

1. 为什么构造函数要放在 private 里?

private:
    Node() { a = 10086; }
  • 目的:禁止外部随意创建对象

  • 如果构造函数是公有的,外部代码可以随意写 Node obj; 或 new Node(),那样就会产生无数个实例,单例模式就被破坏了。放在 private 里,外部就无法直接实例化,只能通过我们提供的 getInstance() 来获取。

2. 为什么要 delete 拷贝构造函数和赋值运算符?

Node(const Node&) = delete;
Node& operator=(const Node&) = delete;
  • 目的:禁止外部复制对象

  • 即使你禁止了构造函数,别人依然可能这样写:Node& n1 = Node::getInstance(); Node n2 = n1;(拷贝构造)或者 n1 = n2;(赋值)。

  • 如果允许复制,内存中就会出现两个内容一样的对象,破坏了“唯一性”。= delete 直接告诉编译器“这两个操作不存在”,如果有人试图调用,编译期就会报错,从根源上杜绝。

3. 为什么要用 static Node& getInstance() 静态函数?

static Node& getInstance() { ... }
  • 目的:提供全局唯一的访问入口

  • 因为构造函数是私有的,外部没有对象,所以必须通过一个属于类本身(不需要对象)的函数来获取实例。static 成员函数正好满足这一点,可以通过 Node::getInstance() 直接调用。

4. 为什么要在函数内部写 static Node instance;?(最精妙的地方)

static Node& getInstance() {
    static Node instance; // 重点在这里
    return instance;
}

这是 Meyers 单例的核心,它同时解决了三个棘手问题:

  • 懒汉式初始化(需要时才创建):这个 instance 变量只有在 第一次调用 getInstance() 时才会被构造。如果程序从头到尾没调用这个函数,这个对象就不会被创建,节省资源。

  • 线程安全(C++11 起):在 C++11 及以后的标准中,函数内静态变量的初始化是线程安全的。即使多个线程同时首次调用 getInstance(),编译器也会保证该对象只被构造一次,不会出现多线程下的“双重检查锁”竞态条件,你不需要手动加锁。

  • 自动销毁与内存安全:这个对象是“静态存储期”的,它会随着程序进程的结束自动调用析构函数销毁,不需要你手动 delete,不会造成内存泄漏。

5. 为什么要返回值是引用(&)而不是指针?

static Node& getInstance()
  • 返回引用比返回指针更安全、语义更明确。它告诉调用者:“这个对象一定存在”,调用时用 . 而不是 ->,代码更简洁,且避免了调用者误以为需要手动 delete 指针。

posted @ 2026-06-28 21:36  家煜宝宝  阅读(22)  评论(0)    收藏  举报