有2个星期没过来了, 这2个星期忙着考试.
言归正传, 今天想写下单例模式, 有时候想写一个完善的单例模式还是需要考虑一些东西的.
1 先看下普通的单例模式:
class TestSingle {
private:
TestSingle();
TestSingle(const TestSingle&);
TestSingle &operator = (const TestSingle&);
public:
static TestSingle* GetInstance() {
static TestSingle s;
return &s;
}
};
- 其中private申明函数来避免通过其它方式构造或者拷贝此类的实例, 在这里只能通过公共函数GetInstance来获取类的实例, 从而确保只有一个实例.
- 通过static来保证每次通过GetInstance只能获取同一份实例.
2 多线程单例
还有一种变种, 有时候希望在单例初始化里面调用一些初始化的功能就要考虑多线程安全的问题了. 还是直接看代码
#include <mutex>
#include <atomic>
class TestSingle {
private:
TestSingle();
TestSingle(const TestSingle&);
TestSingle &operator = (const TestSingle&);
void Init();
public:
static TestSingle* GetInstance() {
if (single_) {
return single_;
}
std::lock_guard<std::mutex> lck (single_mtx_);
if (single_) { // 注意这里需要再次判断, 避免再次初始化
return single_;
}
TestSingle* tmp = new(TestSingle); // 不要直接赋值给single_, 以防别的线程获取到没有初始化的指针
tmp->Init();
single_ = tmp;
return single_;
}
private:
static std::atomic<TestSingle*> single_; // static. 通过atomic达到内存屏障, 避免指令优化, 导致获取未初始化的变量.
static std::mutex single_mtx_; // static
};
3 单例模版
然而单例多了, 每次都这么写一遍就浪费时间了, 能不能抽象出来, 形成一个模版呢, 还是看代码吧.
template < typename T >
class Singleton {
public:
static T* GetInstance() {
static T instance;
return &instance;
}
Singleton(const Singleton&) = delete;
Singleton& operator= (const Singleton) = delete;
protected: // 注意这里的访问权限, 允许子类可以访问, 否则无法创建对象
Singleton() { };
virtual ~Singleton() {std::cout << "deconstructor Singleton" << std::endl; }
};
class Test: public Singleton<Test> {
friend class Singleton<Test>; // 方便访问这里的私有构造函数以及析构函数.
private:
Test(){}
~Test(){std::cout << "deconstructor Test" << std::endl; }
};
int main() {
Test* t = Test::GetInstance();
return 0;
}
网友评论