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指针。

浙公网安备 33010602011771号