单例模式
单例模式下一个类只允许有一个实例。
单例模式
单例模式
单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供了一个全局访问点来访问该实例。
本文基于C++介绍了几种线程安全的单例模式,并实现自动释放内存。
单例模式的C++类,必须实现一个public成员函数返回对象指针,以访问该实例。
基于静态局部变量
基于静态局部变量
实现的单例模式会自动调用析构函数(自动释放内存)。
且这种方法在C++11及之后是线程安全的,C++11之前需要加锁
实现线程安全以避免资源竞争(重复执行静态局部变量的定义语句)。
本身就是线程安全的版本
C++11及之后。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Singleton
{
private:
Singleton() = default;
// Singleton() {}
public:
~Singleton() {}
static Singleton* instance();
};
Singleton* Singleton::instance()
{
static Singleton single; // C++11及之后是线程安全的
return &single; // 返回 指针/地址
}
本身不是线程安全的版本
使用锁实现线程安全
C++11之前需要加锁
实现线程安全。
以C++11引入的std::mutex互斥锁为例,C++11之前无法使用,C++11之前可以使用其他的锁(如Linux内核提供的锁)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <mutex>
class Singleton
{
private:
static std::mutex m_mutex; // 互斥锁
// Singleton() = default;
Singleton() { std::cout << "Singleton()..." << std::endl; }
public:
~Singleton() { std::cout << "~Singleton()..." << std::endl; }
static Singleton* instance();
};
std::mutex Singleton::m_mutex;
// 直接使用std::mutex
Singleton* Singleton::instance()
{
m_mutex.lock(); // 以C++11引入的std::mutex互斥锁为例
std::cout << "lock()..." << std::endl;
static Singleton single;
m_mutex.unlock();
return &single;
}
// 使用std::lock_guard
Singleton* Singleton::instance()
{
std::lock_guard<std::mutex> guard(m_mutex);
std::cout << "lock_guard..." << std::endl;
static Singleton single;
return &single;
}
不使用锁
不使用锁实现线程安全,可以将类的唯一实例定义为静态
(static)成员变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
class Singleton
{
private:
static Singleton m_single;
// Singleton() = default;
Singleton() { std::cout << "Singleton()..." << std::endl; }
public:
~Singleton() { std::cout << "~Singleton()..." << std::endl; }
static Singleton* instance();
};
Singleton Singleton::m_single;
Singleton* Singleton::instance()
{
return &m_single;
}
基于指针
基于指针
实现的单例模式,不会自动调用析构函数,可以实现一个内嵌垃圾回收类。
饿汉实现
饿汉实现:单例类定义的时候就进行了实例化,是线程安全的
。
饿汉
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
class Singleton
{
private:
static Singleton *m_single;
Singleton() { std::cout << "Singleton()..." << std::endl; }
public:
~Singleton() // 不会被调用
{ std::cout << "~Singleton()..." << std::endl; }
static Singleton* instance();
};
Singleton* Singleton::m_single = new Singleton();
Singleton* Singleton::instance()
{
return m_single;
}
实现自动垃圾回收
内嵌圾回收类,自动释放内存。
下面的CGarbo类,就是内嵌圾回收类,Garbo译为垃圾工人。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
class Singleton
{
private:
static Singleton *m_single;
class CGarbo;
static CGarbo m_Cgarbo;
Singleton() { std::cout << "Singleton()..." << std::endl; }
public:
~Singleton() { std::cout << "~Singleton()..." << std::endl; }
static Singleton* instance();
};
class Singleton::CGarbo
{
public:
CGarbo() {}
~CGarbo()
{
if(m_single != nullptr)
delete m_single;
}
};
Singleton::CGarbo Singleton::m_Cgarbo;
Singleton* Singleton::m_single = new Singleton();
Singleton* Singleton::instance()
{
return m_single;
}
懒汉实现
懒汉实现:第一次用到类实例的时候才会去实例化,不是线程安全的,需要通过锁机制
实现线程安全。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <mutex>
class Singleton
{
private:
static Singleton *m_single;
static std::mutex m_mutex; // 锁
class CGarbo // CGarbo类也可以在 Singleton内部实现
{
public:
CGarbo() {}
~CGarbo()
{
if(m_single != nullptr)
delete m_single; // 释放内存
}
};
static CGarbo m_Cgarbo;
Singleton() { std::cout << "Singleton()..." << std::endl; }
public:
~Singleton() { std::cout << "~Singleton()..." << std::endl; }
static Singleton* instance();
};
Singleton::CGarbo Singleton::m_Cgarbo;
std::mutex Singleton::m_mutex;
Singleton* Singleton::m_single = nullptr;
Singleton* Singleton::instance()
{
if(m_single == nullptr) // 避免多次加锁解锁操作
{
std::lock_guard<std::mutex> lock(m_mutex);
std::cout << "lock_guard..." << std::endl;
if(m_single == nullptr)
m_single = new Singleton();
}
return m_single;
}
本文由作者按照 CC BY 4.0 进行授权