单例模式如何实现?

单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。在 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;  
}

注意

  1. 在多线程环境中,上述示例中的 getInstance 方法不是线程安全的。为了确保线程安全,可以使用互斥锁(如 std::mutex)来保护创建实例的代码块。
  2. 在 C++11 及更高版本中,可以使用局部静态变量的方式来实现线程安全的单例模式,因为局部静态变量的初始化是线程安全的。
  3. 析构函数通常不需要设为保护或私有的,因为单例对象应该在程序结束时自动被销毁。但在某些情况下,为了防止外部代码误删单例对象,可以将析构函数设为保护或私有的。如果这样做,需要提供一个静态方法来清理单例对象(如 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_oncestd::once_flag 来保证 getInstance 方法的线程安全性。由于 std::call_once 保证了初始化函数只会被执行一次,因此即使多个线程同时调用 getInstance 方法,也只会有一个线程创建单例对象。

此外,我们还使用了引用 Singleton& 而不是指针 Singleton* 来返回单例对象,这样可以简化代码并减少出错的可能性。由于 std::unique_ptr 已经管理了对象的生命周期,我们不需要担心内存泄漏或其他与内存管理相关的问题。

相关推荐
极光雨雨35 分钟前
【设计模式】单例模式 饿汉式单例与懒汉式单例
单例模式·设计模式
贱贱的剑5 小时前
2.单例模式
单例模式·设计模式
有没有没有重复的名字3 天前
线程安全的单例模式与读者写者问题
java·开发语言·单例模式
小李飞飞砖3 天前
kotlin
开发语言·单例模式·kotlin
想躺平的咸鱼干6 天前
Volatile解决指令重排和单例模式
java·开发语言·单例模式·线程·并发编程
鼠鼠我呀27 天前
【设计模式04】单例模式
单例模式·设计模式
花好月圆春祺夏安7 天前
基于odoo17的设计模式详解---单例模式
单例模式·设计模式
布兰妮甜8 天前
单例模式在前端(JavaScript)中的实现与应用
前端·javascript·单例模式
N_NAN_N9 天前
类图+案例+代码详解:软件设计模式----单例模式
java·单例模式·设计模式
X_StarX9 天前
【Unity笔记01】基于单例模式的简单UI框架
笔记·ui·unity·单例模式·游戏引擎·游戏开发·大学生