C++ 单例模式的设计意图
单例模式(Singleton Pattern) 是一种创建型设计模式,其主要目的是确保一个类只有一个实例,并提供一个全局访问点。单例模式常用于需要全局唯一实例的场景,例如:
- 日志记录器:在整个应用程序中,只需要一个日志记录器实例来记录所有的日志信息。
- 配置管理器:应用程序的配置信息通常只需要一个实例来管理。
- 数据库连接池:在整个应用程序中,只需要一个数据库连接池实例来管理数据库连接。
单例模式的实现方式
单例模式的实现方式主要有两种:懒汉式(Lazy Initialization) 和 饿汉式(Eager Initialization)。
懒汉型单例模式
懒汉式单例模式在第一次使用时才创建实例,因此它具有延迟加载的特性。如果单例对象的创建成本较高,懒汉式可以在需要时才进行创建,从而提高性能。
#include <iostream>
#include <mutex>
class Singleton {
private:
static Singleton* instance;
static std::mutex mtx;
// 构造函数私有化,防止外部创建实例
Singleton() {
std::cout << "Singleton instance created." << std::endl;
}
public:
// 获取单例实例
static Singleton* getInstance() {
// 双重检查锁定,确保线程安全
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mtx);
if (instance == nullptr) {
instance = new Singleton();
}
}
return instance;
}
// 删除拷贝构造函数和赋值运算符,防止拷贝
Singleton(Singleton const&) = delete;
Singleton& operator=(Singleton const&) = delete;
// 销毁实例
static void destroyInstance() {
delete instance;
instance = nullptr;
}
// 测试方法
void showMessage() {
std::cout << "Hello from Singleton!" << std::endl;
}
};
// 静态成员变量初始化
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;
int main() {
Singleton* s1 = Singleton::getInstance();
Singleton* s2 = Singleton::getInstance();
s1->showMessage();
s2->showMessage();
if (s1 == s2) {
std::cout << "s1 and s2 are the same instance." << std::endl;
} else {
std::cout << "s1 and s2 are different instances." << std::endl;
}
Singleton::destroyInstance();
return 0;
}
饿汉型单例模式
饿汉式单例模式在程序启动时就创建实例,而不是在第一次使用时创建。由于实例在程序启动时就创建,因此它的实现相对简单,不需要考虑线程安全问题。
#include <iostream>
class Singleton {
private:
static Singleton* instance;
// 构造函数私有化,防止外部创建实例
Singleton() {
std::cout << "Singleton instance created." << std::endl;
}
public:
// 获取单例实例
static Singleton* getInstance() {
return instance;
}
// 删除拷贝构造函数和赋值运算符,防止拷贝
Singleton(Singleton const&) = delete;
Singleton& operator=(Singleton const&) = delete;
// 销毁实例
static void destroyInstance() {
delete instance;
instance = nullptr;
}
// 测试方法
void showMessage() {
std::cout << "Hello from Singleton!" << std::endl;
}
};
// 静态成员变量初始化
Singleton* Singleton::instance = new Singleton();
int main() {
Singleton* s1 = Singleton::getInstance();
Singleton* s2 = Singleton::getInstance();
s1->showMessage();
s2->showMessage();
if (s1 == s2) {
std::cout << "s1 and s2 are the same instance." << std::endl;
} else {
std::cout << "s1 and s2 are different instances." << std::endl;
}
Singleton::destroyInstance();
return 0;
}
多线程安全版单例模式
多线程安全的单例模式通常采用**双重检查锁定(Double-Checked Locking)**技术,确保在多线程环境下只有一个实例被创建。
#include <iostream>
#include <mutex>
class Singleton {
private:
static Singleton* instance;
static std::mutex mtx;
// 构造函数私有化,防止外部创建实例
Singleton() {
std::cout << "Singleton instance created." << std::endl;
}
public:
// 获取单例实例
static Singleton* getInstance() {
// 双重检查锁定,确保线程安全
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mtx);
if (instance == nullptr) {
instance = new Singleton();
}
}
return instance;
}
// 删除拷贝构造函数和赋值运算符,防止拷贝
Singleton(Singleton const&) = delete;
Singleton& operator=(Singleton const&) = delete;
// 销毁实例
static void destroyInstance() {
delete instance;
instance = nullptr;
}
// 测试方法
void showMessage() {
std::cout << "Hello from Singleton!" << std::endl;
}
};
// 静态成员变量初始化
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;
int main() {
Singleton* s1 = Singleton::getInstance();
Singleton* s2 = Singleton::getInstance();
s1->showMessage();
s2->showMessage();
if (s1 == s2) {
std::cout << "s1 and s2 are the same instance." << std::endl;
} else {
std::cout << "s1 and s2 are different instances." << std::endl;
}
Singleton::destroyInstance();
return 0;
}
总结
- 懒汉式单例模式:在第一次使用时创建实例,适用于实例创建成本较高的情况,但需要考虑线程安全问题。
- 饿汉式单例模式:在程序启动时创建实例,实现简单,线程安全,但可能会导致资源浪费。
- 多线程安全版单例模式:通过双重检查锁定技术确保在多线程环境下只有一个实例被创建。
C++ 多例模式示例代码
多例模式(Multiton Pattern) 是单例模式的一种扩展,它允许多个实例,每个实例都有一个唯一的标识符(例如名称)。通过这种方式,可以在需要多个唯一实例的情况下使用多例模式。
在下面的示例中,我们将创建一个多例模式,使用 std::map
来存储实例和它们的名称。我们将创建固定数量的实例,并在需要时通过名称来获取它们。
代码示例
#include <iostream>
#include <map>
#include <string>
#include <memory>
class Multiton {
private:
// 实例名称
std::string name;
// 构造函数私有化,防止外部创建实例
Multiton(const std::string& name) : name(name) {
std::cout << "Multiton instance created: " << name << std::endl;
}
// 静态成员变量,用于存储多例实例
static std::map<std::string, std::shared_ptr<Multiton>> instances;
public:
// 获取多例实例
static std::shared_ptr<Multiton> getInstance(const std::string& name) {
auto it = instances.find(name);
if (it == instances.end()) {
// 如果实例不存在,创建并存储它
std::shared_ptr<Multiton> instance = std::make_shared<Multiton>(name);
instances[name] = instance;
return instance;
}
return it->second;
}
// 删除拷贝构造函数和赋值运算符,防止拷贝
Multiton(Multiton const&) = delete;
Multiton& operator=(Multiton const&) = delete;
// 测试方法
void showMessage() {
std::cout << "Hello from Multiton " << name << "!" << std::endl;
}
};
// 静态成员变量初始化
std::map<std::string, std::shared_ptr<Multiton>> Multiton::instances;
int main() {
// 创建固定数量的实例,每个实例有一个名称
std::shared_ptr<Multiton> m1 = Multiton::getInstance("Instance1");
std::shared_ptr<Multiton> m2 = Multiton::getInstance("Instance2");
std::shared_ptr<Multiton> m3 = Multiton::getInstance("Instance3");
// 获取已经创建的实例
std::shared_ptr<Multiton> m4 = Multiton::getInstance("Instance1");
std::shared_ptr<Multiton> m5 = Multiton::getInstance("Instance2");
std::shared_ptr<Multiton> m6 = Multiton::getInstance("Instance3");
// 测试方法调用
m1->showMessage();
m2->showMessage();
m3->showMessage();
m4->showMessage();
m5->showMessage();
m6->showMessage();
// 检查实例是否相同
if (m1 == m4 && m2 == m5 && m3 == m6) {
std::cout << "The instances are the same." << std::endl;
} else {
std::cout << "The instances are different." << std::endl;
}
return 0;
}
代码说明
- 私有构造函数:
Multiton
类的构造函数是私有的,防止外部直接创建实例。 - 静态成员变量
instances
:使用std::map
存储实例名称和对应的实例指针。 getInstance
方法:通过名称获取实例。如果实例不存在,则创建并存储它。showMessage
方法:用于测试实例是否正常工作。
输出结果
运行上述代码后,输出结果将显示每个实例的创建信息,并验证通过相同名称获取的实例是否相同。
Multiton instance created: Instance1
Multiton instance created: Instance2
Multiton instance created: Instance3
Hello from Multiton Instance1!
Hello from Multiton Instance2!
Hello from Multiton Instance3!
Hello from Multiton Instance1!
Hello from Multiton Instance2!
Hello from Multiton Instance3!
The instances are the same.
总结
多例模式通过 std::map
存储多个实例,每个实例都有一个唯一的标识符(例如名称)。通过这种方式,可以在需要多个唯一实例的情况下使用多例模式,并且可以方便地通过标识符获取实例。