C++ 设计模式复习 ----单例模式

C++ 单例模式的原理与实现

单例模式 (Singleton) 是一种设计模式,它确保一个类只有一个实例,并提供一个全局访问点。单例模式通常用于全局配置、日志管理等需要在整个应用程序中共享资源的场景。

单例模式的原理

单例模式的核心思想是保证类只生成一个实例,这可以通过以下几个步骤来实现:

  1. 私有化构造函数:将类的构造函数定义为私有,以防止外部对象创建该类的实例。
  2. 提供一个静态方法获取实例:通过类的静态方法创建并返回该类的唯一实例,确保实例的唯一性。
  3. 静态指针存储唯一实例:使用静态指针存储类的唯一实例,静态数据在类的所有对象中是共享的,因此它在整个程序中都存在。

单例模式的实现方式

下面是单例模式在 C++ 中的经典实现方式:

1. 饿汉式单例

饿汉式单例在程序启动时就创建了唯一的实例,这样可以确保线程安全,但会在没有实际使用该实例时浪费内存。

#include 

class Singleton {
private:
    static Singleton* instance;  // 静态成员变量存储唯一实例

    // 构造函数私有化,防止外部实例化
    Singleton() {
        std::cout << "Singleton instance created." << std::endl;
    }

public:
    // 提供一个静态方法来获取唯一实例
    static Singleton* getInstance() {
        return instance;
    }
};

// 在类外初始化静态成员变量
Singleton* Singleton::instance = new Singleton();

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();

    if (s1 == s2) {
        std::cout << "s1 and s2 are the same instance." << std::endl;
    }
    return 0;
}

说明

  • 构造函数被定义为私有,防止外部直接创建对象。
  • getInstance() 静态方法返回唯一的实例。
  • 实例在类加载时就创建,称为饿汉式单例。

2. 懒汉式单例(线程不安全)

懒汉式单例是延迟加载的,即在第一次使用时才创建实例,这样可以避免在不需要时浪费内存。

#include 

class Singleton {
private:
    static Singleton* instance;

    Singleton() {
        std::cout << "Singleton instance created." << std::endl;
    }

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

Singleton* Singleton::instance = nullptr;

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();

    if (s1 == s2) {
        std::cout << "s1 and s2 are the same instance." << std::endl;
    }
    return 0;
}

说明

  • getInstance() 方法中,当 instancenullptr 时才创建实例,这样可以延迟实例的创建。
  • 这种实现方式在多线程环境下是不安全的,多个线程可能同时创建实例。

3. 线程安全的懒汉式单例

为了使懒汉式单例在多线程环境下安全,可以使用互斥锁(mutex)来防止多个线程同时创建实例。

#include 
#include 

class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;

    Singleton() {
        std::cout << "Singleton instance created." << std::endl;
    }

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

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

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();

    if (s1 == s2) {
        std::cout << "s1 and s2 are the same instance." << std::endl;
    }
    return 0;
}

说明

  • 使用 std::mutex 来保证在多线程环境下,只有一个线程能创建实例,从而确保线程安全。
  • std::lock_guard 是一种 RAII 类型的锁,可以确保互斥锁在作用域结束时自动释放。

4. C++11 静态局部变量单例(推荐方式)

C++11 之后,静态局部变量的初始化是线程安全的,使用这种方式可以实现更简洁和高效的线程安全单例。

#include 

class Singleton {
private:
    Singleton() {
        std::cout << "Singleton instance created." << std::endl;
    }

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

int main() {
    Singleton& s1 = Singleton::getInstance();
    Singleton& s2 = Singleton::getInstance();

    if (&s1 == &s2) {
        std::cout << "s1 and s2 are the same instance." << std::endl;
    }
    return 0;
}

说明

  • getInstance() 方法中使用静态局部变量 instance,在第一次调用时进行初始化,且 C++11 确保了其线程安全性。
  • 这种实现方式是最推荐的,因为它既简洁又高效,并且是线程安全的。

单例模式的应用场景

  • 配置管理类:系统中需要共享配置参数,使用单例模式可以保证所有模块访问相同的配置实例。
  • 日志系统:应用程序中的日志通常是全局的,通过单例模式可以方便地管理日志的输出。
  • 资源管理:如数据库连接池、线程池等,使用单例可以避免重复创建资源。

单例模式的优缺点

优点

  • 唯一实例:确保系统中只有一个实例,减少内存开销,避免资源冲突。
  • 全局访问:提供全局访问点,便于管理共享资源。

缺点

  • 隐藏依赖:单例模式使得类的依赖不明确,可能导致代码的可测试性降低。
  • 难以扩展:单例类通常不易继承,因为它的构造函数是私有的。

总结

单例模式是一种常用的设计模式,可以用于管理系统中的共享资源。它的实现方式有多种,包括饿汉式、懒汉式、线程安全的懒汉式以及 C++11 的静态局部变量实现。在现代 C++ 开发中,推荐使用静态局部变量的方式来实现单例,因为它既简洁又高效,并且能自动保证线程安全。

你可能感兴趣的:(C++学习,c++,设计模式,单例模式)