C++单例模式及实例
单例模式是非常常用的设计模式,通俗讲就是保证全局仅存在一份类型实例。
我们通过模板类来实现泛型单例模式,所有单例类对象存储在static变量中,全局静态变量要早于main方法之前初始化,且只初始化一次,因此只要调用类似HungrySingleton<log>::GetInstance() 这样的语句即可获取单例对象log 的指针。
对于C++来说,需要保证单例类HungrySingleton 和LazySingleton 构造函数、析构函数、拷贝和赋值通通不可用,因此其继承了一个删除了上述方法的父类,从而禁止二者调用。
饿汉式比较容易处理,只需要在类体外进行相应的定义即进行了初始化。由于static对象只进行一次初始化,因此饿汉式自身保证了线程安全性。
懒汉式需要考虑线程安全的问题,当真正用到时才需要进行实例化,这个实例化过程需要保证线程安全。方法是在检测到对象不存在时加锁,并再一次检测,如果真的不存在,则进行实例化。确保实例化后可以从静态对象中安全取出单例对象。
**已废弃方法:**当然,不要忘了delete ,我们可以在static初始化时创建一个Garbage 类,其负责在单例对象生命期结束时,回收相应资源。
2/18日修改:上述通过调用另一个静态Garbage对象来删除Instance在实测中无法调用析构函数,改为使用智能指针来正确释放
#include <pthread.h>
#include <iostream>
#include <memory>
class NonInstantiatable {
public:
NonInstantiatable() = delete;
~NonInstantiatable() = delete;
NonInstantiatable(const NonInstantiatable&) = delete;
NonInstantiatable& operator=(const NonInstantiatable&) = delete;
};
template<typename T>
class HungrySingleton : public NonInstantiatable{
public:
static std::shared_ptr<T> GetInstance();
private:
static std::shared_ptr<T> Instance;
};
template<typename T>
std::shared_ptr<T> HungrySingleton<T>::Instance(new T);
template<typename T>
std::shared_ptr<T> HungrySingleton<T>::GetInstance() {
return Instance;
}
class MutexImpl {
public:
MutexImpl() {
std::cout<< "mutex created" << std::endl;
pthread_mutex_init(&m_mutex, nullptr);
}
void Lock() {
pthread_mutex_lock(&m_mutex);
}
void Unlock() {
pthread_mutex_unlock(&m_mutex);
}
~MutexImpl() {
std::cout<< "mutex cleared" << std::endl;
pthread_mutex_destroy(&m_mutex);
}
private:
pthread_mutex_t m_mutex;
};
template<typename T>
class LazySingleton : public NonInstantiatable{
public:
static std::shared_ptr<T> GetInstance();
private:
static std::shared_ptr<T> Instance;
static std::unique_ptr<MutexImpl> Mutex;
};
template<typename T>
std::shared_ptr<T> LazySingleton<T>::Instance(nullptr);
template<typename T>
std::unique_ptr<MutexImpl> LazySingleton<T>::Mutex(new MutexImpl);
template<typename T>
std::shared_ptr<T> LazySingleton<T>::GetInstance() {
if(!Instance) {
Mutex->Lock();
if(!Instance) {
LazySingleton<T>::Instance.reset(new T);
}
Mutex->Unlock();
}
return Instance;
}
template<typename T>
class Singleton : public NonInstantiatable{
public:
static T* GetInstance() {
static T v;
return &v;
}
};
#define NUM 20
#include "singleton.h"
#include <iostream>
#include <unistd.h>
#include <sys/syscall.h>
class Log {
public:
Log() {
std::cout << "Log Initialed" << std::endl;
}
~Log() {
std::cout << "Log cleared" << std::endl;
}
};
void* test(void* data) {
auto log = HungrySingleton<Log>::GetInstance();
std::cout << "pthread:" << syscall(SYS_gettid) << "log address" << log.get() << std::endl;
return NULL;
}
int main(int argc, char** argv) {
pthread_t t[NUM];
for(int i = 0; i < NUM; ++i) {
pthread_create(&t[0] + i, 0, test, NULL);
}
for(int i = 0; i < NUM; ++i) {
pthread_join(t[i], NULL);
}
return 0;
}
|