源码见文章底部。
class singleton 声明了一个静态引用 static T & m_instance;
这个静态引用是用来干嘛的呢?注意到该文件末尾有如下代码:
template<class T>
T & singleton< T >::m_instance = singleton< T >::get_instance();
读到这里应该大概能理解了,该引用只是为了使用static
的特性,该全局对象在程序初始化之前就进行了实例化了对象。
单例函数get_instance()
方位属性为private
。内部有如下定义 class singleton_wrapper : public T {};
将T的构造函数保护了起来。先将静态成员赋值然后在堆中构造对象,静态成员指向他。
is_destroyed()
主要作用是对生命周期做控制管理。
而template <class T> static void use(T const *)
只是为了消除未初始化的警告,可参考另一工具类
boost::template <typename... Ts>void ignore_unused()
的使用。最后调用构造生成实例对象并返回其引用。
// refer to instance, causing it to be instantiated (and
// initialized at startup on working compilers)
BOOST_ASSERT(! is_destroyed());
// note that the following is absolutely essential.
// commenting out this statement will cause compilers to fail to
// construct the instance at pre-execution time. This would prevent
// our usage/implementation of "locking" and introduce uncertainty into
// the sequence of object initializaition.
use(& m_instance);
if (!t)
t = new singleton_wrapper;
return static_cast<T &>(*t);
class singleton的析构函数负责清理资源。
下面的代码为测试简单的简单的静态对象单例模式与boost::serialization::singleton的区别
#include <boost/serialization/singleton.hpp>
#include <iostream>
template<typename T>
class singleton_test
{
private:
T tt;
public:
T& get_instance() { return tt; }
};
class TEST_CLASS1
{
public:
TEST_CLASS1() { std::cout << __FUNCTION__ << std::endl; }
~TEST_CLASS1(){ std::cout << __FUNCTION__ << std::endl; }
void print() { std::cout << "hello, im TEST_CLASS1" << std::endl; }
};
class TEST_CLASS2
{
public:
TEST_CLASS2() { std::cout << __FUNCTION__ << std::endl; }
~TEST_CLASS2() { std::cout << __FUNCTION__ << std::endl; }
void print() { std::cout << "hello, im TEST_CLASS2" << std::endl; }
};
int main()
{
std::cout << "begin main:" << std::endl;
boost::serialization::singleton<TEST_CLASS2> t2;
singleton_test<TEST_CLASS1> t1;
t1.get_instance().print();
t2.get_mutable_instance().print();
std::cout << "end main:" << std::endl;
}
测试结果如图:
可知boost库的单件在程序入口点(main)之前已经完成构造。而两者析构顺序与声明顺序相关(逆序)。
boost库的单件源码(版本boost_1_66_0)
template <class T>
class singleton : public singleton_module
{
private:
static T & m_instance;
// include this to provoke instantiation at pre-execution time
static void use(T const *) {}
static T & get_instance() {
// use a wrapper so that types T with protected constructors
// can be used
class singleton_wrapper : public T {};
// Use a heap-allocated instance to work around static variable
// destruction order issues: this inner singleton_wrapper<>
// instance may be destructed before the singleton<> instance.
// Using a 'dumb' static variable lets us precisely choose the
// time destructor is invoked.
static singleton_wrapper *t = 0;
// refer to instance, causing it to be instantiated (and
// initialized at startup on working compilers)
BOOST_ASSERT(! is_destroyed());
// note that the following is absolutely essential.
// commenting out this statement will cause compilers to fail to
// construct the instance at pre-execution time. This would prevent
// our usage/implementation of "locking" and introduce uncertainty into
// the sequence of object initializaition.
use(& m_instance);
if (!t)
t = new singleton_wrapper;
return static_cast<T &>(*t);
}
static bool & get_is_destroyed(){
static bool is_destroyed;
return is_destroyed;
}
public:
BOOST_DLLEXPORT static T & get_mutable_instance(){
BOOST_ASSERT(! is_locked());
return get_instance();
}
BOOST_DLLEXPORT static const T & get_const_instance(){
return get_instance();
}
BOOST_DLLEXPORT static bool is_destroyed(){
return get_is_destroyed();
}
BOOST_DLLEXPORT singleton(){
get_is_destroyed() = false;
}
BOOST_DLLEXPORT ~singleton() {
if (!get_is_destroyed()) {
delete &(get_instance());
}
get_is_destroyed() = true;
}
};
template<class T>
T & singleton< T >::m_instance = singleton< T >::get_instance();
} // namespace serialization
} /
https://blog.csdn.net/u012508160/article/details/79127729