简述
- 单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点。提供全局访问点就是在类中定义一个静态成员函数,返回在类内部唯一构造的实例。单例式分为懒汉式和饿汉式。
懒汉式
- 懒汉式:在需要构造实例才进行初始化,比如说用户调用GetInstance方法获取一个唯一实例,这个时候在函数内部才使用new进行构造对象。
- 懒汉式举例(线程不安全):
#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:缺陷是第一个内存管理这个地方还需要手动释放,第二个是每个获取单例的线程都会上锁
#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;
}
- 懒汉式线程安全版本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;
}
饿汉式
- 饿汉式:程序加载进内存运行就创建唯一实例,通过在全局作用域中直接对静态成员变量进行初始化。
- 饿汉式举例(线程安全)
#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;
}