c++单例模式

  • Post author:
  • Post category:其他




要点:

  • 1、构造函数私有化,防止从类外调用构造函数,保证在任何情况下只生成一个实例

  • 2、提供一个全局的静态方法getInstance(全局访问点),便于提供从类外部获取单例类的唯一实例的方法

  • 3、在类中定义一个静态指针,指向本类的变量的静态变量指针

  • 4、禁止拷贝构造


  • 单例模式有许多种实现方法:

    a. 懒汉式:使用的时候才创建,多线程访问的时候线程不安全(双检锁)

    b. 饿汉式:类文件加载的时候创建对象,如果对象一直没有使用,则类对象浪费空间


  • 特点与选择:

    a. 如果要进行线程同步,访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。

    b. 在访问量较小时,采用懒汉实现。这是以时间换空间。



懒汉式单例

// 懒汉式
class Singleton1
{
private:
    static Singleton1 *instance; //定义指针
    Singleton1() { std::cout << "Singleton1的构造" << std::endl; }
    // 销毁实例
    static void destoryInstance()
    {
        if (instance != NULL) {
            delete instance;
            instance = NULL;
        }
    }
    // 禁用拷贝构造和移动构造
    Singleton1(Singleton1 &) = delete;
    Singleton1 &operator=(const Singleton1 &) = delete;

public:
    //定义一个公有接口,返回本类对象的指针
    static Singleton1 *getInstance()
    {
        if (instance == nullptr) {
            instance = new Singleton1();
        }
        return instance;
    }
};

  • 存在问题:

    a. 懒汉式只能在单线程下工作,如果两个线程同时判断

    instance == nullptr

    ,并且instance在此时确实没有创建,那么两个线程都会创造一个实例,避免上述问题的方法是在判断时加上同步锁即可。

    b. 需要手动调用delete回收实例内存,如不手动调用delete,可改用智能指针.



加锁的懒汉式


  • 要点:

    • 引入`static std::shared_ptr 析构时自动回收资源,无需手动释放资源
    • 双重锁是为了提高效率,第一次判断是为了判断是否创建实例,我们只是在实例没有创建之前需要加锁操作,实例创建之后就不需要加锁了;第二次判断是为了判断是否重复创建;
// 加锁的懒汉式
class Singleton2
{
private:
    static std::shared_ptr<Singleton2> instance; //定义指针
    static std::mutex mtx;

    Singleton2() { std::cout << "Singleton2的构造" << std::endl; }

    // 禁用拷贝构造和移动构造
    Singleton2(Singleton2 &) = delete;
    Singleton2 &operator=(const Singleton2 &) = delete;

public:
    // 定义一个公有接口,返回本类对象的指针
    static std::shared_ptr<Singleton2> getInstance()
    {
        // 双重检测锁,第一次判断是为了判断是否创建实例,我们只是在实例没有创建之前需要加锁操作,实例创建之后就不需要加锁了
        if (instance == nullptr) {
            std::lock_guard<std::mutex> lck(mtx); // 离开作用域后自动解锁
            // 第二次判断是为了判断是否重复创建
            if (instance == nullptr) {
                instance = std::shared_ptr<Singleton2>(new Singleton2());
            }
        }
        return instance;
    }
};



源码

#include <iostream>
#include <memory> // C++11 shared_ptr头文件
#include <mutex>  // C++11 mutex头文件

// 懒汉式
class Singleton1
{
private:
    static Singleton1 *instance; //定义指针
    Singleton1() { std::cout << "Singleton1的构造" << std::endl; }
    // 销毁实例
    static void destoryInstance()
    {
        if (instance != NULL) {
            delete instance;
            instance = NULL;
        }
    }
    // 禁用拷贝构造和移动构造
    Singleton1(Singleton1 &) = delete;
    Singleton1 &operator=(const Singleton1 &) = delete;

public:
    //定义一个公有接口,返回本类对象的指针
    static Singleton1 *getInstance()
    {
        if (instance == nullptr) {
            instance = new Singleton1();
        }
        return instance;
    }
};

// 加锁的懒汉式
class Singleton2
{
private:
    static std::shared_ptr<Singleton2> instance; //定义指针
    static std::mutex mtx;

    Singleton2() { std::cout << "Singleton2的构造" << std::endl; }

    // 禁用拷贝构造和移动构造
    Singleton2(Singleton2 &) = delete;
    Singleton2 &operator=(const Singleton2 &) = delete;

public:
    // 定义一个公有接口,返回本类对象的指针
    static std::shared_ptr<Singleton2> getInstance()
    {
        // 双重检测锁,第一次判断是为了判断是否创建实例,我们只是在实例没有创建之前需要加锁操作,实例创建之后就不需要加锁了
        if (instance == nullptr) {
            std::lock_guard<std::mutex> lck(mtx); // 离开作用域后自动解锁
            // 第二次判断是为了判断是否重复创建
            if (instance == nullptr) {
                instance = std::shared_ptr<Singleton2>(new Singleton2());
            }
        }
        return instance;
    }
};

// 饿汉式
class Singleton3
{
private:
    static Singleton3 *instance; //定义指针

    Singleton3() { std::cout << "Singleton3的构造" << std::endl; }

    // 禁用拷贝构造和移动构造
    Singleton3(Singleton3 &) = delete;
    Singleton3 &operator=(const Singleton3 &) = delete;

public:
    // 定义一个公有接口,返回本类对象的指针
    static Singleton3 *getInstance() { return instance; }
};

Singleton1 *Singleton1::instance = nullptr;
std::shared_ptr<Singleton2> Singleton2::instance = nullptr;
std::mutex Singleton2::mtx;
Singleton3 *Singleton3::instance = new Singleton3();

int main()
{
    {
        auto instance1 = Singleton1::getInstance();
        auto instance2 = Singleton1::getInstance();
        // instance1 与instance2 相同,构造函数只调用一次
        std::cout << "instance1: " << instance1 << std::endl;
        std::cout << "instance2: " << instance2 << std::endl;
    }

    {
        auto instance1 = Singleton2::getInstance();
        auto instance2 = Singleton2::getInstance();
        // instance1 与instance2 相同,构造函数只调用一次
        std::cout << "instance1: " << instance1 << std::endl;
        std::cout << "instance2: " << instance2 << std::endl;
    }

    {
        auto instance1 = Singleton3::getInstance();
        auto instance2 = Singleton3::getInstance();
        // instance1 与instance2 相同,构造函数只调用一次
        std::cout << "instance1: " << instance1 << std::endl;
        std::cout << "instance2: " << instance2 << std::endl;
    }
    return 0;
}



版权声明:本文为qq_45601625原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。