简述

  1. 单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点。提供全局访问点就是在类中定义一个静态成员函数,返回在类内部唯一构造的实例。单例式分为懒汉式和饿汉式。

懒汉式

  1. 懒汉式:在需要构造实例才进行初始化,比如说用户调用GetInstance方法获取一个唯一实例,这个时候在函数内部才使用new进行构造对象。
  2. 懒汉式举例(线程不安全):
#include<iostream>
class singeleton
{
private:
    inline singeleton()
    {
        std::cout<<"懒汉式举例"<<std::endl;
    }
    static singeleton * ptr;
public:
    inline static singeleton * GetInstance()
    {
        if(ptr == NULL)
        {
            ptr = new singeleton;
        }
        return ptr;
    }
    //释放内存
    inline static void FreeInstance()
    {
        if(ptr != NULL)
        {
            delete ptr;
        }
    }

};
singeleton * singeleton::ptr = NULL;
int main()
{
    singeleton * pointer1 = singeleton::GetInstance();
    singeleton * pointer2 = singeleton::GetInstance();
    if(pointer1 == pointer2)
    {
        std::cout<<"是同一对象"<<std::endl;
    }
    else
    {
        std::cout<<"不是同一对象"<<std::endl;
    }
    singeleton::FreeInstance();
    return 0;
}

// 手工对在堆上分配的内存进行释放,操作不当容易造成资源泄漏。
//对懒汉式进行改进的案例如下,在单例类中定义析构资源类来完成对在堆上分配的内存的释放
#include<iostream>

class singeleton
{
private:
    static singeleton* ptr;
    int lengh;

    inline singeleton()
    {
        std::cout << "The singeleton's constructor are called" << std::endl;
        lengh = 10;
    }

    class Destroy
    {
    public:
        inline ~Destroy()
        {
            if (ptr != NULL)
            {
                delete ptr;
                std::cout << "堆上分配内存析构已成功" << std::endl;
            }
        }

        Destroy()
        {
            std::cout << "The destroy's constructor are called" << std::endl;
        }
    };
    static Destroy des;
public:
    inline static singeleton* GetInstance()
    {
        if (ptr == NULL)
        {
            ptr = new singeleton();
        }
        return ptr;
    }

    inline int GetLengh()const
    {
        return lengh;
    }
};
//静态成员初始化
singeleton* singeleton::ptr = NULL;
// 必须
singeleton::Destroy singeleton::des;

int main()
{
    singeleton* pointer = singeleton::GetInstance();
    std::cout << pointer->GetLengh() << std::endl;
    std::cout << singeleton::GetInstance() << std::endl;
    std::cout << pointer << std::endl;
    return 0;
}

  1. 懒汉式线程安全版本之1:缺陷是第一个内存管理这个地方还需要手动释放,第二个是每个获取单例的线程都会上锁
#include <iostream>
#include <mutex>
#include <thread>

std::mutex m;

class Singleton {
private:
    static Singleton* instance;
    
    Singleton() {
        std::cout << "懒汉式举例" << std::endl;
    }
public:
    inline static Singleton* getInstance() {
        std::unique_lock<std::mutex> lock(m);
        if (nullptr == instance) {
            instance = new Singleton();
        }
        if (lock.owns_lock()) lock.unlock();
        return instance;
    }
    inline static void freeInstance() {
        if (nullptr != instance)
            delete instance;
    }
};

// 静态成员变量的初始化
Singleton* Singleton::instance = nullptr;

void func() {
    Singleton* instance = Singleton::getInstance();
    std::cout << instance << std::endl;
}
int main() {
    std::thread t1(func);
    std::thread t2(func);
    std::thread t3(func);

    t1.join();
    t2.join();
    t3.join();

    func();
    Singleton::freeInstance();
    return 0;
}
  1. 懒汉式线程安全版本2:使用call_once函数
#include <iostream>
#include <mutex>    // for call_once
#include <thread>   // for class thread
#include <memory>   // for shared_ptr
std::once_flag g_flag;

class Singleton {
public:
    static Singleton* getInstance() {
        std::call_once(g_flag, [&]() {
            p_instance.reset(new Singleton());
            std::cout << "initial success\n";
            });
        return p_instance.get();
    }
private:
    static std::shared_ptr<Singleton> p_instance;
};

std::shared_ptr<Singleton> Singleton::p_instance;

void func() {
    std::cout << Singleton::getInstance() << std::endl;
}
int main() {
    // test
    std::thread t1(func);
    std::thread t2(func);
    std::thread t3(func);
    std::thread t4(func);

    t1.join();
    t2.join();
    t3.join();
    t4.join();


    return 0;
}

饿汉式

  1. 饿汉式:程序加载进内存运行就创建唯一实例,通过在全局作用域中直接对静态成员变量进行初始化。
  2. 饿汉式举例(线程安全)
#include<iostream>
class singeleton
{
private:
    static singeleton * ptr;

    inline singeleton()
    {
        std::cout<<"饿汉式举例"<<std::endl;
    }
public:
    inline static singeleton * GetInstance()
    {
        return ptr;
    }

    inline static void FreeInstance()
    {
        if(ptr != NULL)
        {
            delete ptr;
            std::cout<<"堆上分配内存析构已成功"<<std::endl;
        }
    }
};
singeleton*  singeleton::ptr = new singeleton();

int main()
{
    singeleton * pointer1 = singeleton::GetInstance();
    singeleton * pointer2 = singeleton::GetInstance();
    if(pointer1 == pointer2)
    {
        std::cout<<"是同一对象"<<std::endl;
    }
    else
    {
        std::cout<<"不是同一对象"<<std::endl;
    }
    singeleton::FreeInstance();
    
    return 0;
}