单例模式的实现--C++
实现单例模式
只能生成一个实例的类是实现了单例模式的类型
//(1)只适合单线程环境的的单例模式实现
class Singleton
{
private:
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
private:
static Singleton* instance;
public:
static Singleton* Instance()
{
if (instance == nullptr) //这个地方多线程是时候有可能出现错误。
{
instance = new Singleton();
}
return instance;
};
};
Singleton* Singleton::instance = nullptr;
//以上的范例只适合在单线程下操作,如果在多线程中多个线程同时运行到判断instance
//是否为nullptr的if语句,并且instance的确没有创建时,那么多个线程都会创建一个
//一个实例,此时类型Singleton就不再满足单例模式的需求了。且此类型Singleton的写法
//会存在内存泄露的问题。
//针对内存泄露的问题,我们有以下两种解决方法。
//(1.1)解决内存泄露的第一种方式:智能指针解决内存泄露问题
#include<memory>
using namespace std;
class Singleton
{
private:
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
private:
static shared_ptr<Singleton> instance;
public:
static shared_ptr<Singleton> Instance()
{
if (instance == nullptr) //这个地方多线程是时候有可能出现错误。
{
instance = make_shared<Singleton>();
}
return instance;
};
};
shared_ptr<Singleton> Singleton::instance = nullptr;
//将instance定义为智能指针的形式,则不会出现内存泄露的问题。
//(1.2) 解决内存泄露的第二种方式,利用类中类和静态成员结合的方式
class Singleton
{
private:
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
private:
static Singleton* instance;
private:
class Deletor
{
public:
~Deletor()
{
if (Singleton::instance != nullptr)
{
delete Singleton::instance;
Singleton::instance = nullptr;
}
}
};
static Deletor deletor;
public:
static Singleton* Instance()
{
if (instance == nullptr) //这个地方多线程是时候有可能出现错误。
{
instance = new Singleton();
}
return instance;
};
};
Singleton* Singleton::instance = nullptr;
//这样在程序运行结束的时候,会调用deletor的析构函数,
//该函数会删除单例的唯一的实例。
#include<mutex>
using namespace std;
class Singleton
{
private:
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
private:
static Singleton* instance;
static mutex my_mutex;
private:
class Deletor
{
public:
~Deletor()
{
if (Singleton::instance != nullptr)
{
delete Singleton::instance;
Singleton::instance = nullptr;
}
}
};
static Deletor deletor;
public:
static Singleton* Instance()
{
my_mutex.lock(); //对这一部分的代码进行加锁,以免创建多个对象
if (instance == nullptr)
{
instance = new Singleton();
}
my_mutex.unlock();
return instance;
};
};
Singleton* Singleton::instance = nullptr;
mutex Singleton::my_mutex;
//以上的方式可用于多线程的程序中,但是效率不是太高,因为
//在第一次创建了一个实例之后,之后每次使用接口,都需要再加锁。
//可以修改成以下的双判断加锁方式
#include<mutex>
using namespace std;
class Singleton
{
private:
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
private:
static Singleton* instance;
static mutex my_mutex;
private:
class Deletor
{
public:
~Deletor()
{
if (Singleton::instance != nullptr)
{
delete Singleton::instance;
Singleton::instance = nullptr;
}
}
};
static Deletor deletor;
public:
static Singleton* Instance()
{
if (instance == nullptr)
{
my_mutex.lock(); //对这一部分的代码进行双判断加锁,提高性能。
//除了第一次使用接口,其他使用接口时再也不会进行加锁。
if (instance == nullptr)
{
instance = new Singleton();
}
my_mutex.unlock();
}
return instance;
};
};
Singleton* Singleton::instance = nullptr;
mutex Singleton::my_mutex;
//but,以上的代码仍然可能会存在问题。
//在某些内存模型中(虽然不常见)或者是由于编译器的优化以及运行时优化等等原因,
//使得instance虽然已经不是nullptr但是其所指对象还没有完成构造,
//这种情况下,另一个线程如果调用getInstance()就有可能使用到一个不完全初始化的对象。
//因为C++11规定了local static在多线程条件下的初始化行为,要求编译器保证内部静态变量的线程安全性。
//所以我们将代码修改成以下:
#include<mutex>
using namespace std;
class Singleton
{
private:
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
public:
static Singleton& Instance()
{
static Singleton instance;
return instance;
};
};
posted on 2021-10-07 09:53 xcxfury001 阅读(56) 评论(0) 收藏 举报
浙公网安备 33010602011771号