单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。在 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
已经管理了对象的生命周期,我们不需要担心内存泄漏或其他与内存管理相关的问题。