目录
什么是单例模式
一个类只能有一个实例
要点
1. 构造函数(以及拷贝构造函数、赋值运算符)设为private
2. 类内部定义一个静态实例
其它注意事项
多线程情况下需要防止同时创建实例
实现
1.饿汉式
思想:一开始就创建了对象,每次要用时直接返回这个对象。
优点:没有多线程问题
缺点:如果一直没用到这个类,那么一开始就创建对象是浪费空间。
#include<iostream>
using namespace std;
class A{
private:
A(int v):value(v){};
A(){};
A(A const&); // 或设为delete
A& operator=(A const&); // 或设为delete
static A* instance; // 也可以不用指针:static A instance;
public:
static A* getInstance(){ // 返回指针
return instance;
}
/* 也可以返回实例的引用(不能返回一个非引用的对象)
static A& getInstance(){
return *instance;
}
*/
int value;
};
A* A::instance = new A(5); // 在初始化时创建实例
// A A::instance(5); // 对应instance不是指针的写法
// A A::instance; // 对应instance不是指针且构造函数没有参数的写法(虽然这句什么都没做,但不能少,否则这个静态变量没有初始化,会报错)
int main()
{
A *a = A::getInstance(), *b = A::getInstance();
a->value = 7; // 修改a的值
cout<<a<<' '<<a->value<<endl; // 输出a的地址和value
cout<<b<<' '<<b->value<<endl; // 输出b的地址和value
getchar();getchar();
return 0;
}
输出
a和b的地址相同,说明指向同一个实例
2.懒汉式
思想:第一次使用时才创建对象
优点:如果没被调用就不会占用内存。
缺点:多线程情况下可能同时创建对象,不满足单例的定义。
class A{
private:
A(){};
A(A const&);
A& operator=(A const&);
static A* instance;
public:
static A* getInstance(){
if(instance == nullptr)
instance = new A();
return instance;
}
};
A* A::instance = nullptr;
3.线程安全的懒汉式
两次检查(double check) + 使用互斥锁
缺点:只有当没有创建对象并且大量线程同时访问时,该锁才会影响性能。
class A{
private:
A(){};
A(A const&);
A& operator=(A const&);
static A* instance;
public:
static A* getInstance(){
if(instance == nullptr){
lock(); // 只是方便描述, 可执行代码可以用std::lock_guard<std::mutex> lk(m_mutex);
if(instance == nullptr)
instance = new A();
unlock(); // 如果加锁操作是上面注释中的代码,则这里不需要unlock
}
return instance;
}
};