Singleton 单例模式
单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。
一个简单的实现:
template<typename T>
T& instance()
{
static std::unique_ptr<T> instance{new T{}};
return *instance;
}
这里我们在函数内部定义了一个局部静态变量(local static),它只有在instance第一次被使用时才会创建实例。c++11 也规定了local static是线程安全的, 如果我们用godbolt去看一下汇编,会看到:
movzx eax, BYTE PTR guard variable for int& instance<int>()::instance[rip]
...
mov edi, OFFSET FLAT:guard variable for int& instance<int>()::instance
call __cxa_guard_acquire
...
call operator new(unsigned long)
...
call std::unique_ptr<int, std::default_delete<int> >::unique_ptr<std::default_delete<int>, void>(int*)
mov edi, OFFSET FLAT:guard variable for int& instance<int>()::instance
call __cxa_guard_release
...
call __cxa_atexit
它保证了并发的线程会等待初始化的完成。non-local static object 的初始化发生在main函数之前,所以不存在线程安全问题,但是以如果你有多个non-local static对象,他们的初始化顺序是随机的。
另外也可以写成类模板,这样其他类就可以以crtp的方式继承单例类并且拥有单例的特性:
template<typename T>
class Singleton
{
protected:
Singleton() noexcept = default;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
// to silence base class Singleton<T> has a non-virtual destructor [-Weffc++]
virtual ~Singleton() = default;
public:
static T& get_instance() noexcept(std::is_nothrow_constructible<T>::value)
{
// Guaranteed to be destroyed. Instantiated on first use. Thread safe in C++11
static T instance;
return instance;
}
};
class TradeServer : public Singleton<TradeServer>
{
}
为什么不直接继承然后用virtual 的 get_instance()
, 因为会产生vtable,增大了内存使用空间,同时增加了vtable跳转,性能下降。