C++ 单例模式 实现

单例模式 (来自ChatGPT)

单例模式的定义

单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。

单例模式的特点

  • 单一实例:单例模式确保一个类只有一个实例。
  • 全局访问点:单例模式提供一个全局访问点来访问该实例。
  • 延迟初始化:单例模式可以延迟初始化实例,直到第一次访问时。
  • 线程安全:单例模式可以确保实例的线程安全。

单例模式的优点

  • 资源共享:单例模式可以共享资源,减少内存的使用。
  • 性能优化:单例模式可以提高性能,减少实例的创建和销毁。
  • 简化代码:单例模式可以简化代码,减少代码的复杂度。

单例模式的缺点

  • 耦合度高:单例模式可能会增加耦合度,影响代码的可维护性。
  • 不利于测试:单例模式可能会使得测试变得困难。
  • 不利于扩展:单例模式可能会限制代码的扩展性。

单例实现

Meyer’s Singleton(线程安全)

使用静态局部变量来确保线程安全。这是 C++ 中最常用的单例模式实现方法。

class Singleton {
public:
    static Singleton& getInstance() {
        static Singleton instance;
        return instance;
    }

private:
    Singleton() {}
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
};

双重检查锁单例 Double-Checked Locking Singleton(线程安全)

使用双重检查锁机制来减少获取锁的开销。这是一种高效的单例模式实现方法,但需要注意锁的粒度性能

class Singleton {
public:
    static Singleton& getInstance() {
        if (!instance) {
            std::lock_guard<std::mutex> lock(mutex);
            if (!instance) {
                instance = new Singleton();
            }
        }
        return *instance;
    }

private:
    Singleton() {}
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    static Singleton* instance;
    static std::mutex mutex;
};

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex;

Lazy Initialization Singleton(不安全)

不使用任何同步机制,直接返回实例。这是一种简单的单例模式实现方法,但不安全,可能会导致多个实例创建。

class Singleton {
public:
    static Singleton& getInstance() {
        if (!instance) {
            instance = new Singleton();
        }
        return *instance;
    }

private:
    Singleton() {}
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    static Singleton* instance;
};

Singleton* Singleton::instance = nullptr;

Enum-Based Singleton(线程安全)

使用枚举来确保单例实例只创建一次。这是一种巧妙的单例模式实现方法,但需要注意枚举的使用场景。

class Singleton {
public:
    static Singleton& getInstance() {
        return instance;
    }

private:
    enum class SingletonEnum { INSTANCE };
    static Singleton instance;
};

Singleton Singleton::instance;

Bill Pugh Singleton(线程安全)

使用嵌套类来确保单例实例只创建一次。这是一种高效的单例模式实现方法,但需要注意嵌套类的使用场景。

class Singleton {
public:
    static Singleton& getInstance() {
        return SingletonHelper::instance;
    }

private:
    class SingletonHelper {
    public:
        static Singleton instance;
    };

    Singleton() {}
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
};

Singleton Singleton::SingletonHelper::instance;

std::call_once Singleton(线程安全)

使用 std::call_once 来确保单例实例只创建一次。这是一种高效的单例模式实现方法,但需要注意 std::call_once 的使用场景。

class Singleton {
public:
    static Singleton& getInstance() {
        std::call_once(flag, []() {
            instance = new Singleton();
        });
        return *instance;
    }

private:
    Singleton() {}
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    static Singleton* instance;
    static std::once_flag flag;
};

Singleton* Singleton::instance = nullptr;
std::once_flag Singleton::flag;

单例模式出现线程不安全的原因及解决方法

单例模式出现线程不安全的原因

  1. 双重检查锁定:在多线程环境中,多个线程可能同时尝试创建单例类的实例。为了防止这种情况,双重检查锁定机制经常被使用。但是,如果不正确地实现这种机制,可能会出现线程不安全的情况。
  2. 同步方法:如果单例类具有同步方法,它可能会在多线程环境中引发性能瓶颈甚至死锁。
  3. 延迟初始化:延迟初始化是一种常用的单例实现技术,但是如果不正确地实现,可能会出现线程不安全的情况。例如,如果多个线程同时尝试初始化单例实例,可能会创建多个实例。
  4. 静态初始化:如果单例实例使用静态块或静态方法进行初始化,在多线程环境中可能会出现线程不安全的情况。如果多个线程同时访问单例实例,可能会出现多个实例被创建的情况。

单例模式出现线程不安全的解决方法

  1. 同步方法:使用同步方法来确保只有一个线程可以创建单例实例。
  2. 双重检查锁定与volatile:使用volatile变量来确保对instance变量的更改对所有线程可见。
  3. 按需持有者初始化:使用持有者类来延迟初始化单例实例,确保只有一个实例被创建。
  4. 枚举单例:使用枚举来实现单例模式,这提供了一个线程安全的实现。

你可能感兴趣的:(C++,c++,单例模式,开发语言,设计模式)