**懒汉式构造单例类**
懒汉式,指的就是需要时再构造(延迟构造),在效率上会优于饿汉式,因为饿汉式在进入 main 之前就要构造,懒汉式不用。
基本特点是:线程不安全
基本模板(加锁):
#include <bits/stdc++.h>
#define rep( i , j , n ) for ( int i = int(j) ; i < int(n) ; ++i )
#define dew( i , j , n ) for ( int i = int(n-1) ; i > int(j) ; --i )
#define _PATH __FILE__ , __LINE__
typedef std::pair < int , int > P ;
using std::cin ;
using std::cout ;
using std::endl ;
using std::string ;
class Entity final {
public:
// 获取单例类实例的入口
static Entity *getInstance() {
if ( null == nullptr ) {
myMutex.lock() ;
if ( null == nullptr ) {
null = new Entity ;
}
myMutex.unlock() ;
}
return null ;
}
private:
// 构造函数设为 private
explicit Entity() = default ;
~Entity() noexcept = default ;
Entity(const Entity &) = delete ;
Entity& operator=(const Entity &) = delete ;
Entity& operator=(const Entity &&) = delete ;
class Litter {
public:
~Litter() {
cout << "\n清理单例类" << endl ;
if ( null not_eq nullptr )
delete null ;
null = nullptr ;
}
} ;
private:
static Entity *null ;
// GC 清理类
static Litter litter ;
// 设置一把锁
static std::mutex myMutex ;
} ;
Entity* Entity::null ;
Entity::Litter Entity::litter ;
std::mutex Entity::myMutex ;
int main () {
constexpr int N = 10 ;
Entity *Instance[N] ;
rep ( i , 0 , N )
Instance[i] = Entity::getInstance() ;
rep ( i , 0 , N )
cout << "Instance[ " << i << " ] = " << Instance[i] << endl ;
rep ( i , 0 , N )
Instance[i] = nullptr ;
return 0 ;
}
优点:双检锁,保证了线程安全;两次判断是否为 nullptr, 避免多次加锁解锁。
缺点:频繁的加解锁操作,损失了性能。
两种单例模式的分析比较参考:单例模式的分析
2018.8.3
C++11 的 std::call_once 和 std::once_flag 搭配使用,可以保证在多个线程中,只构造一次,具体实现如下:
static Entity *getInstance() {
try {
static std::once_flag flag ;
std::call_once(flag, [&](){
cout << "构造单例类\n\n" ;
null = new Entity ;
}) ;
if ( null == nullptr )
throw std::bad_alloc() ;
} catch ( std::exception &e ) {
cout << e.what() << endl ;
}
return null ;
}
程序运行结果: