单例模式如何实现?

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

相关推荐
GGBondlctrl3 天前
【JavaEE初阶】深入解析单例模式中的饿汉模式,懒汉模式的实现以及线程安全问题
单例模式·设计模式·饿汉模式·懒汉模式·懒汉模式线程安全问题
清风拂山感3 天前
设计模式之单例模式
javascript·单例模式·设计模式
陌上之殇3 天前
C++实现单例模式
c++·单例模式
冷白白3 天前
【C++】单例模式
开发语言·c++·单例模式·c
枪哥玩转嵌入式4 天前
大佬,简单解释下“嵌入式软件开发”和“嵌入式硬件开发”的区别
单片机·单例模式·51单片机
It'sMyGo4 天前
js设计模式-工厂模式 单例模式 观察者模式 发布订阅模式 原型模式 代理模式 迭代器模式
观察者模式·单例模式·设计模式
我与岁月的森林5 天前
继承实现单例模式的探索(二)
单例模式·c#
小狗爱世界5 天前
常用设计模式之单例模式、策略模式、工厂模式
单例模式·设计模式·策略模式
湖南罗泽南5 天前
设计模式之单例模式
单例模式·设计模式
还算善良_5 天前
【设计模式】单例模式
java·单例模式·设计模式