概念
单例模式(Singleton Pattern)是一种设计模式,确保一个类只有一个实例,并提供一个全局访问点。它常用于需要控制资源访问的场景,如数据库连接、日志记录或者配置管理等。
方式
懒汉式单例
懒汉式单例是在第一次被请求时创建实例。为了确保线程安全,通常使用 std::mutex 进行保护。
#include <iostream>
#include <mutex> class Singleton {
public: // 禁止拷贝构造和赋值 Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; static Singleton& getInstance() { static Singleton instance; // 此时实例在第一次调用时创建 return instance; } void someMethod() { std::cout << "Doing something in Singleton." << std::endl; } private: Singleton() { std::cout << "Singleton Constructor" << std::endl; // 建构函数 } ~Singleton() { std::cout << "Singleton Destructor" << std::endl; // 析构函数 }
}; int main() { Singleton::getInstance().someMethod(); // 访问单例 return 0;
}
代码解析
- 私有构造函数:确保外部不能直接创建实例。
- 禁止拷贝:复制构造函数和赋值运算符被删除,以防止复制。
- 静态局部变量:在静态方法 getInstance 中声明一个静态局部变量,这个变量 在第一次使用时初始化,后续调用将返回相同的实例。
- 线程安全:C++11 及以上版本中,局部静态变量在多线程中是安全的,不需要额外的锁。
饿汉式单例
饿汉式单例在程序启动时就创建实例,不论是否被使用。这样可以避免多线程中的同步问题,但在资源使用上可能会浪费。
#include <iostream> class Singleton {
public: // 禁止拷贝构造和赋值 Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; static Singleton& getInstance() { return instance; // 直接返回实例 } void someMethod() { std::cout << "Doing something in Singleton." << std::endl; } private: Singleton() { std::cout << "Singleton Constructor" << std::endl; // 建构函数 } ~Singleton() { std::cout << "Singleton Destructor" << std::endl; // 析构函数 } static Singleton instance; // 静态实例
}; // 定义静态成员
Singleton Singleton::instance; int main() { Singleton::getInstance().someMethod(); // 访问单例 return 0;
}
代码解析
- 静态实例:在类的内部声明一个静态成员 instance,在类外定义该成员。
- 构造函数:与懒汉式相同,构造函数和析构函数是私有的,以防止外部实例化。
线程安全的懒汉式单例(使用锁)
这种方法在创建单例实例时使用互斥锁来实现控制,确保多个线程不同时创建。
#include <iostream>
#include <mutex> class Singleton {
public: static Singleton* getInstance() { std::lock_guard<std::mutex> lock(mu); // 加锁 if (!instance) instance = new Singleton(); // 延迟加载 return instance; } void someMethod() { std::cout << "Doing something in Singleton." << std::endl; } private: Singleton() = default; // 私有构造函数 ~Singleton() = default; // 私有析构函数 Singleton(const Singleton&) = delete; // 禁止拷贝构造 Singleton& operator=(const Singleton&) = delete; // 禁止赋值 static Singleton* instance; // 静态实例指针 static std::mutex mu; // 互斥量
}; // 定义静态成员
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mu; int main() { Singleton::getInstance()->someMethod(); // 访问单例 return 0;
}
代码解析
- 互斥量:使用 std::mutex 控制访问,以实现线程安全。每当访问 getInstance 时,lock_guard 自动加锁。
- 动态分配:实例在首次访问时通过 new 创建,依赖用户在适当的位置调用 delete 销毁对象。
采用 std::call_once
C++11 中引入的 std::call_once 可以确保线程安全的单例实现。
#include <iostream>
#include <mutex> class Singleton {
public: static Singleton& getInstance() { std::call_once(initInstanceFlag, &Singleton::initSingleton); return *instance; } void someMethod() { std::cout << "Doing something in Singleton." << std::endl; } private: Singleton() { std::cout << "Singleton Constructor" << std::endl; } ~Singleton() { std::cout << "Singleton Destructor" << std::endl; } static void initSingleton() { instance = new Singleton(); } static Singleton* instance; static std::once_flag initInstanceFlag; // 初始化标志
}; // 静态成员初始化
Singleton* Singleton::instance = nullptr;
std::once_flag Singleton::initInstanceFlag; int main() { Singleton::getInstance().someMethod(); return 0;
}
代码解析
- std::once_flag:用于保证指定的函数只被调用一次。
- std::call_once:确保在多线程环境下只会初始化一次实例。
总结
单例模式可以通过多种方式实现,包括懒汉式、饿汉式、线程安全的懒汉式、使用 std::call_once 等。选择合适的实现方式主要取决于项目的需求、线程安全需求以及如何管理生命周期等因素。对于大多数情况,使用 C++11 提供的懒汉式结合 std::call_once 是最推荐的做法,因为它既保证了线程安全,又简洁易懂。