C++ 单例模式续
Posted CPP进阶之旅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ 单例模式续相关的知识,希望对你有一定的参考价值。
单例模式代码详解
针对上篇文章中的C++单例模式实例代码,这里对几个版本进行详细分析介绍。
版本一:
这个版本如果在单线程情况下使用,则是一种非常简便的方式,这里只需要将无参构造函数和拷贝构造函数私有化就可以了。
但是在多线程情况下,这种实现方式是线程不安全的。
如果线程A与线程B同时构造对象,当线程A的调用getinstance还没执行完m_instance=new Singleton();这句代码,这时候m_instance依旧为null,所以线程B在构造对象的时候就会再次执行m_instance=new Singleton();这时就可能产生两个对象,因此违背了单例模式的定义。
版本二:
这种方式下,使用了加锁的方法,当多个线程调用GetInstance()时,保证了只有一个线程可以执行if及其后面的语句,而其他的线程只能暂时阻塞,因此也就保证了对象的唯一性。
但是,当我们创建完对象后,每次需要读取该对象的时候依旧需要加锁和释放锁,这样就会造成 一定的性能问题。
版本三:
这种实现方式看起来很完美,既解决了上面版本一的线程不安全问题,又避免多多次加锁而造成的的性能浪费,只有在第一次必要的时候才会使用锁,真是棒极了。
因此,在相当长的一段时间,这个版本迷惑了很多人。
直到后来,人们发现这种方式存在漏洞,以为编译器优化导致了内存读写的乱序执行。
对于m_instance = new Singleton()这代码可以分成三个步骤来执行:
1、分配一个Singleton类型对象所需要的内存。
2、在分配的内存处构造Singleton类型的对象。
3、把分配的内存的地址赋给指针m_instance。
一般情况下,我们都认为这三个步骤是按顺序执行的,但实际上只能确定步骤1是最先执行的,步骤2,3却不一定。
这样当多线程同时执行时,如果线程A没有按照1 2 3的顺序而是按照 1 3 2的顺序执行,当线程A执行完步骤3后就认为m_instance不再是空指针,而线程B也不再执行实例的构造,这时候线程B继续执行return m_instance,但是这个对象并没有真正的被构造,也就产生了Bug。
版本四:
针对上面版本四中的问题在c++ 11版本中加入了automic这样一种原子操作,也就解决了上面的问题。
以上是关于C++ 单例模式续的主要内容,如果未能解决你的问题,请参考以下文章
C++ 单例模式
c++单例模式
c++单例模式
c++单例模式
设计模式--单例模式C++实现
单例模式之C++实现