剑指Offer-题2-实现单例模式
题目:实现单例(Singleton)模式
设计一个类,我们只能生成该类的一个实例
解析
题目要求明显,设计单例模式:仅生成单个实例
如此需要考虑一下几点:
- 构造函数需“隐藏”,且另设方法通过静态变量判断是否创建实例充当构造函数
- 返回实例的方法必定使用
new
创建实例(否则将产生值传递生成多个单例),故需存储静态实例指针待销毁时使用 - 静态变量用于存储变量创建状态,将其设为
int flag
?此举造成冗余,不如利用静态实例指针
理清三点后奉上本人渣码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
31class Singleton
{
public:
~Singleton();
static Singleton* s_pInstance;
static Singleton* getInstance();
private:
Singleton();
// other members......
}
// C++中仅有静态整形常量才可于类内初始化,否则导致所有实例均含该静态成员
Singleton* Singleton::s_pInstance = nullptr;
Singleton::Singleton() {}
Singleton::~Singleton()
{
if (nullptr != Singleton::s_pInstance)
{
delete Singleton::s_pInstance;
Singleton::s_pInstance = nullptr;
}
}
Singleton* Singleton::getInstance()
{
if (nullptr == Singleton::s_pInstance)
Singleton::s_pInstance = new Singleton();
return Singleton::s_pInstance;
}
看似完美,却木有考虑多线程下同时执行 if (nullptr == Singleton::s_pInstance)
情况,加锁加锁……1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// 使用window API操控锁
class LockBase
{
public:
LockBase()
{
::InitializeCriticalSection(&cs);
}
~LockBase()
{
::DeleteCriticalSection(&cs);
}
void lock()
{
::EnterCriticalSection(&cs);
}
void unlock()
{
::LeaveCriticalSection(&cs);
}
private:
CRITICAL_SECTION cs;
};
1 | class Singleton |
very nice ! 😀 等等!其实这个锁的范围有点大了,我们可以再次优化,缩小范围1
2
3
4
5
6
7
8
9
10
11
12Singleton* Singleton::getInstance()
{
if (nullptr == Singleton::s_pInstance)
{
LockBase lockBase;
lockBase.lock();
if (nullptr == Singleton::s_pInstance)
Singleton::s_pInstance = new Singleton();
lockBase.unlock();
}
return Singleton::s_pInstance;
}
不但缩小范围,而且提升效率,感觉很棒棒(๑•̀ㅂ•́)و✧ 对照下书本
有木有搞错!结果书上说还有更加优秀的解法=_=
力荐解法一:利用静态构造函数
静态构造函数:定义类时仅自动执行一次的函数
可能要让您失望了,书中使用C#,而C++没有静态构造函数!😂
先看看书中C#神级代码1
2
3
4
5
6
7
8
9public class Singleton
{
private static Singleton instance = new Singleton();
public static Singleton getInstance()
{
return instance;
}
// other members......
};
再看看 C++
模拟代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class Singleton
{
public:
~Singleton();
static Singleton* s_pInstance;
static Singleton* getInstance();
private:
Singleton();
// other members......
};
Singleton* Singleton::s_pInstance = new Singleton();
Singleton* Singleton::getInstance()
{
return Singleton::s_pInstance;
}
其实是在全局域中直接设定,略显牵强😝
力荐解法二:实现按需创建实例
解法一中过早创建实例占用内存,所以可用高级语言中 类仅在使用时载入 的特性改进代码
C++无法实现此方法,以下依旧是书中C#神级代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class Singleton
{
public static Singleton getInstance()
{
return Nested.instance;
}
class Nested
{
// internal表示该变量仅可在同项目内调用
internal static Singleton instance = new Singleton();
};
// other members......
};
本题扩展
实现可继承单例,派生类都只能产生一个实例
可以在单例类中使用指针数组判断对应子类标记是否已存在,若存在直接返回,反之创建子类,应加锁实现
本文采用 CC BY-NC-SA 3.0 Unported 协议进行许可