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++实现