单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。在 C++ 中,可以通过将构造函数设为私有,并提供一个静态方法来获取或创建类的实例来实现单例模式。
下面是一个简单的 C++ 单例模式的实现示例:
#include <iostream>
#include <mutex> // 用于线程安全(可选)
class Singleton {
private:
// 私有的静态指针,指向单例对象
static Singleton* instance;
// 私有的构造函数,防止外部创建实例
Singleton() {}
// 私有的拷贝构造函数和赋值运算符,防止拷贝
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
// 静态互斥锁(可选,用于多线程环境)
static std::mutex mtx;
public:
// 静态方法,用于获取单例对象
static Singleton* getInstance() {
// 使用互斥锁保证线程安全(可选)
std::lock_guard<std::mutex> lock(mtx);
// 如果实例不存在,则创建它
if (instance == nullptr) {
instance = new Singleton();
}
return instance;
}
// 其他公共成员函数...
void doSomething() {
std::cout << "Singleton is doing something." << std::endl;
}
// 静态析构函数(可选),用于在程序结束时清理单例对象
// 注意:C++11 开始支持静态成员和局部对象的析构函数,但通常不推荐这样做
// 因为在程序结束时,所有资源都应该被自动清理
static void destroyInstance() {
if (instance != nullptr) {
delete instance;
instance = nullptr;
}
}
// 析构函数设为保护或私有的(可选),防止外部删除实例
protected:
~Singleton() {
// 单例对象销毁时的清理工作(如果有的话)
}
};
// 初始化静态成员(在类外部)
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;
// 使用示例
int main() {
Singleton* s1 = Singleton::getInstance();
Singleton* s2 = Singleton::getInstance();
// s1 和 s2 指向同一个对象
if (s1 == s2) {
std::cout << "s1 and s2 are the same instance." << std::endl;
}
s1->doSomething(); // 调用单例对象的成员函数
// 在程序结束时,可以调用 destroyInstance 来清理单例对象(通常不推荐)
// Singleton::destroyInstance();
return 0;
}
注意:
- 在多线程环境中,上述示例中的
getInstance
方法不是线程安全的。为了确保线程安全,可以使用互斥锁(如std::mutex
)来保护创建实例的代码块。 - 在 C++11 及更高版本中,可以使用局部静态变量的方式来实现线程安全的单例模式,因为局部静态变量的初始化是线程安全的。
- 析构函数通常不需要设为保护或私有的,因为单例对象应该在程序结束时自动被销毁。但在某些情况下,为了防止外部代码误删单例对象,可以将析构函数设为保护或私有的。如果这样做,需要提供一个静态方法来清理单例对象(如
destroyInstance
),但这通常不推荐,因为它可能导致资源泄漏或其他问题。
在 C++11 及以后的版本中,我们可以使用更简洁和线程安全的方式来实现单例模式。以下是一个基于 C++11 的线程安全单例模式的实现示例:
#include <iostream>
#include <memory>
#include <mutex>
class Singleton {
private:
// 静态成员指针,指向单例对象
static std::unique_ptr<Singleton> instance;
// 私有的构造函数
Singleton() {}
// 禁止拷贝和移动
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(Singleton&&) = delete;
public:
// 静态方法,用于获取单例对象
static Singleton& getInstance() {
// 使用 std::call_once 来保证线程安全
static std::once_flag flag;
std::call_once(flag, [] {
instance.reset(new Singleton());
});
return *instance;
}
// 其他成员函数...
void doSomething() {
std::cout << "Singleton is doing something." << std::endl;
}
// 不需要显式销毁单例,unique_ptr 会在程序结束时自动处理
};
// 初始化静态成员(在类外部)
std::unique_ptr<Singleton> Singleton::instance;
// 使用示例
int main() {
Singleton& s1 = Singleton::getInstance();
Singleton& s2 = Singleton::getInstance();
// s1 和 s2 引用同一个对象
if (&s1 == &s2) {
std::cout << "s1 and s2 are the same instance." << std::endl;
}
s1.doSomething(); // 调用单例对象的成员函数
return 0;
}
在这个实现中,我们使用了 std::unique_ptr
来管理单例对象的生命周期,确保在程序结束时能够自动释放内存。同时,我们使用了 std::call_once
和 std::once_flag
来保证 getInstance
方法的线程安全性。由于 std::call_once
保证了初始化函数只会被执行一次,因此即使多个线程同时调用 getInstance
方法,也只会有一个线程创建单例对象。
此外,我们还使用了引用 Singleton&
而不是指针 Singleton*
来返回单例对象,这样可以简化代码并减少出错的可能性。由于 std::unique_ptr
已经管理了对象的生命周期,我们不需要担心内存泄漏或其他与内存管理相关的问题。