单例模式(Singleton Pattern),属于创建型模式,是最简单的设计模式之一。单例模式设计的类,在一个进程中只能产生一个实例。
单例模式有以下特点:
根据它的三个特点,可以写出以下代码:
class Singleton
{
public:
static Singleton* getInstance()
{
if (_instance == nullptr)
_instance = new Singleton;
return _instance;
}
private:
static Singleton* _instance;
Singleton(){ }
~Singleton(){ }
Singleton(const Singleton&) = delete;
Singleton(const Singleton&&) = delete;
};
Singleton* Singleton::_instance = nullptr;
上面代码通过把构造和析构函数用private来修饰,并把左值拷贝和右值拷贝delete,让单例对象不能随便构造和析构,通过提供的静态方法getInstance可以获取全局唯一的实例对象。
但在我们程序执行正常结束的过程中,单例对象的析构对象并没有被调用到。在我们的单例对象析构函数刷新某些资源,或者写日志记录对象状态之类必须在析构函数中做工作,这样的实现方式是不能满足的。
因此,我们可以在构造这个全局的唯一实例时,注册一个atexit回调,在程序结束时调用实例的析构函数:
#include
using namespace std;
class Singleton
{
public:
static Singleton* getInstance()
{
if (_instance == nullptr)
{
_instance = new Singleton;
atexit(recovery);
}
return _instance;
}
private:
static void recovery() { delete _instance; }
static Singleton* _instance;
Singleton(){ }
~Singleton() { cout << "~Singleton" << endl; }
Singleton(const Singleton&) = delete;
Singleton(const Singleton&&) = delete;
};
Singleton* Singleton::_instance = nullptr;
int main()
{
Singleton::getInstance();
}
在多线程环境下,一个判空操作是无法保证我们单例模式的只有一个实例对象的特性的,很有可能会出现创建多个实例的情况,这时我们需要在创建实例时加上锁,一般采用锁加双重判断的方式实现:
class Singleton
{
public:
static Singleton* getInstance()
{
if (_instance == nullptr)
{
lock_guard<mutex> lock(_mutex);
if (_instance == nullptr)
{
_instance = new Singleton;
atexit(recovery);
}
}
return _instance;
}
private:
static void recovery() { delete _instance; }
static Singleton* _instance;
static mutex _mutex;
Singleton(){ }
~Singleton() { cout << "~Singleton" << endl; }
Singleton(const Singleton&) = delete;
Singleton(const Singleton&&) = delete;
};
Singleton* Singleton::_instance = nullptr;
mutex Singleton::_mutex;
_instance = new Singleton;底层的执行需要经过这个三个步骤:
在执行这三条语句的时候,编译器、CPU为了优化可能会改变这三条语句的执行顺序进行重排,这样在执行完3,2还为执行时,另一个线程检测到_instance != nullptr,就会返回一个未初始化完成的一个对象,这样不安全,可以使用C++11提供的内存序来进行控制,包含在atomic头文件中


#include
#include
#include
using namespace std;
class Singleton
{
public:
static Singleton* getInstance()
{
if (_instance.load(memory_order_acquire) == nullptr)//本线程后续所有的读操作都要在本条原子操作完成后执行
{
lock_guard<mutex> lock(_mutex);
if (_instance.load(memory_order_relaxed) == nullptr)//内部
{
// 1. 开辟内存空间
// 2. 调用构造函数初始化
_instance.store(new Singleton, memory_order_release);//本线程之前所有的写操作完成后才执行本条原子操作 3. 返回Singleton指针
atexit(recovery);
}
}
return _instance.load(memory_order_relaxed);
}
private:
static void recovery() { delete _instance; }
static atomic<Singleton*> _instance;
static mutex _mutex;
Singleton(){ }
~Singleton() { cout << "~Singleton" << endl; }
Singleton(const Singleton&) = delete;
Singleton(const Singleton&&) = delete;
};
atomic<Singleton*> Singleton::_instance;
mutex Singleton::_mutex;
int main()
{
cout << Singleton::getInstance() << endl;
cout << Singleton::getInstance() << endl;
Singleton::getInstance();
}
定义静态局部对象,只有运行到了才会加载,由系统来提供静态成员线程安全行的保证,并会在程序结束时调用其析构函数。
#include
using namespace std;
class Singleton
{
public:
static Singleton* getInstance()
{
static Singleton instance;
return &instance;
}
private:
static Singleton* _instance;
Singleton() { }
~Singleton() { cout << "~Singleton" << endl; }
Singleton(const Singleton&) = delete;
Singleton(const Singleton&&) = delete;
};
int main()
{
cout << Singleton::getInstance() << endl;
cout << Singleton::getInstance() << endl;
Singleton::getInstance();
}