zoukankan      html  css  js  c++  java
  • C++实现Creational Singleton模式

    http://patmusing.blog.163.com/blog/static/135834960201002322226231/

    1. C++实现Creational - Singleton模式  

    2010-01-23 02:22:26|  分类: Pattern |  标签:c++设计模式  |字号 订阅

     
     

    Singleton设计模式经常被大家谈及,很多人认为该模式很简单。的确,从纯粹的设计模式的角度来看,它并不复杂,但是从实现的角度来看,其实非常不简单,尤其是用C++去实现它的时候。

     

    一、Java版本的Singleton模式实现

    我们不妨先看看在Java中实现Singleton模式的典型代码:

    // Singleton设计模式典型代码

    package Singleton;

    public class Singleton

    {

             private Singleton(){}

     

             private static Singleton instance = null;

             public static synchronized Singleton getInstance()

             {

                       if(instance == null)

                       {

                                instance = new Singleton();

                       }

                       return instance;

             }

    }

     

    // 测试Singleton

    package Singleton;

    public class PatternClient

    {

             public static void main(String args[])

             {

                       Singleton sg = Singleton.getInstance();

             }

    }

     

    从上面的代码,可以看出,在Singleton类中:

    1.       构造方法是private的;

    2.       有一个private的静态变量,其类型就是Singleton本身;

    3.       有一个public的方法getInstance(),其返回类型是Singleton

    4.       必须注意getInstance()有关键字synchronized修饰,以提供线程安全。

    1. C++实现Singleton模式 - 玄机逸士 - 玄机逸士博客 

    下面我们来看看如何在C++中实现Singleton设计模式。

    二、最简单的实现方式

    先看下面的代码,并注意相关的注释:

    // Singleton.h

    // C++:最简单的方式实现Singleton设计模式

    #include <string>

    #include <iostream>

    using namespace std;

    class Singleton

    {

    private:

             Singleton()                                            // private构造函数

             {

                       cout << "Singleton::Constructor" << endl;

             }

     

             static Singleton* sg;                               // 私有静态变量,其类型为Singleton*

                                                                         // 形如Singleton sg;这样的声明会出编译时错误

    public:

             static Singleton* getInstance()                 // public成员函数getInstance()

             {

                       cout << "Singleton::getInstance" << endl;

                       if(!sg)

                       {

                                sg = new Singleton();           // (1)在这个地方new了一个对象,但是在什么地方delete呢?

                       }

     

                       return sg;

             }

    };

     

    // 测试Singleton的代码:Singleton.cpp

    #include "Singleton.h"

    // 用下面的方式对静态私有成员变量sg进行初始化,此时sg不指向任何对象

    Singleton* Singleton::sg = 0;

    int main(void)

    {

             Singleton *sg = Singleton::getInstance();

     

             return 0;

    }

     

    关于如何在一个类的定义中,使用类本身作为类型对成员变量进行声明的详细情况,请见:

    http://blog.csdn.net/pathuang68/archive/2009/11/24/4866945.aspx

     

    上面的Singleton的实现至少存在一个问题:

    语句(1)new了一个对象,但没有被delete,因此肯定会造成内存泄漏。而在Java语言中由于有内存回收机制,所以不存在这个问题。不过既然是Singleton,通常都是和应用程序的生命周期是基本一致的,因此,实践中可以不考虑这个“内存泄露”问题,因为它根本没有机会造成真正意义上的泄露;另一方面,从纯技术的完备性角度来看,我们则需要解决这样的问题。

     

    三、使用auto_ptr来解决内存泄漏问题

    关于auto_ptr的原理和使用方法,请参考:

    http://blog.csdn.net/pathuang68/archive/2009/11/29/4898101.aspx

    http://blog.csdn.net/pathuang68/archive/2009/11/29/4900321.aspx

     

    // Singleton.h

    #include <memory>

    #include <string>

    #include <iostream>

    using namespace std;

     

    // C++:使用auto_ptr实现Singleton设计模式

    class Singleton

    {

    private:

             Singleton()                                                                                 // private构造函数

             {

                       cout << "Singleton::Constructor" << endl;

             }

     

             static auto_ptr<Singleton> sg;                                                     // 私有静态变量,其类型为auto_ptr<Singleton>

     

    public:

             static auto_ptr<Singleton> getInstance()                                       // public成员函数getInstance()

             {                                                                                                // 返回类型为auto_ptr<Singleton>

                       cout << "Singleton::getInstance" << endl;

                       if(!sg.get())                                                                        // 判断sg所指的对象是否为空

                       {

           // 此处不能直接写成auto_ptr<Singleton> sg(new Singleton);

                                auto_ptr<Singleton> temp(new Singleton);

                                sg = temp;                                             

                       }

     

                       return sg;

             }

    };

     

    // Singleton.cpp:测试Singleton的代码

    #include "Singleton.h"

     

    // 用下面的方式对静态私有成员变量sg进行初始化,此时sg不指向任何对象

    auto_ptr<Singleton> Singleton::sg;

    int main(void)

    {

             // singleton就是我们需要的对象

             auto_ptr<Singleton> singleton(Singleton::getInstance());

     

             return 0;

    }

     

    这样以来,由于引入了auto_ptr,因此不会存在内存泄漏问题。进一步地,我们还可以将Singleton类,写成模板类,这样就可以更加灵活了。为此,我们另外增加一个类Student用来测试,Singleton模板类。

    // Singleton.h

    #include <memory>

    #include <string>

    #include <iostream>

    using namespace std;

     

    class Student

    {

    public:

             Student(const string name = "Andrew"const int age = 7) : name(name), age(age)

             {

                       cout << "constructor..." << endl;

             }

     

             void print_info() const

             {

                       cout << "Name: " << name << ", Age: " << age << endl;

             }

    private:

             string name;

             int age;

    };

     

    // Singleton模板类

    template<typename T>

    class Singleton

    {

    private:

             Singleton()                                                                                           // private构造函数

             {

                       cout << "Singleton::Constructor" << endl;

             }

     

             static auto_ptr<T> sg;                                                                          // 私有静态变量,其类型为auto_ptr<T>

     

    public:

             static auto_ptr<T> getInstance()                                                           // public成员函数getInstance()

             {                                                                                                         // 返回类型为auto_ptr<T>

                       cout << "Singleton::getInstance" << endl;

                       if(!sg.get())                                                                                // 判断sg所指的对象是否为空

                       {

                                // 此处不能直接写成auto_ptr<T> sg(new T);

                                auto_ptr<T> temp(new T);        

                                sg = temp;                                             

                       }

     

                       return sg;

             }

    };

     

     

    // Singleton.cpp 测试代码

    #include "Singleton.h"

    // 用下面的方式对静态私有成员变量sg进行初始化,此时sg不指向任何对象

    auto_ptr<Student> Singleton<Student>::sg;

     

    int main(void)

    {

             auto_ptr<Student> singleton(Singleton<Student>::getInstance());

             singleton->print_info();

     

             return 0;

    }

    经过测试,上面的代码证明是可行的。

     

     

    四、使用boost::mutex来解决线程安全性问题

    Java代码中,有一个synchronized关键字,这个关键字的作用就是确保线程安全,很明显上面的代码尽管解决了内存泄漏的问题,但决线程安全方面的问题依然存在。

     

    C++语言中,本身并不存在线程的概念,需要借助一些函数库才能实现,这种函数库有很多,其中一个比较出色的就是boost中的线程库了。boost库本身是可以跨操作系统平台的。

     

    参考下面的代码和注释:

    // Singleton.h

    #include <memory>

    #include <string>

    #include <iostream>

    #include <boost/thread/thread.hpp>

    #include <boost/thread/mutex.hpp>

    using namespace std;

     

    boost::mutex sglt_mutex;

     

    class Student

    {

    public:

             Student(const string name = "Andrew"const int age = 7) : name(name), age(age)

             {

                       cout << "constructor..." << endl;

             }

     

             void print_info() const

             {

                       cout << "Name: " << name << ", Age: " << age << endl;

             }

    private:

             string name;

             int age;

    };

     

     

    template<typename T>

    class Singleton

    {

    private:

             Singleton()                                                                                           // private构造函数

             {

                       cout << "Singleton::Constructor" << endl;

             }

     

             static auto_ptr<T> sg;                                                                           // 私有静态变量,其类型为auto_ptr<T>

     

    public:

             static auto_ptr<T> getInstance()                                                             // public成员函数getInstance()

             {                                                                                                           // 返回类型为auto_ptr<T>

                       // 加锁,只有当前线程可以获取sg,其他线程均被阻塞(block)

                       // 直到当前线程执行sglt_mutex.unlock()

                       sglt_mutex.lock();                                                                         // (1)

                       cout << "Singleton::getInstance" << endl;

                       if(!sg.get())                                                                                  // 判断sg所指的对象是否为空

                       {

                                // 此处不能直接写成auto_ptr<T> sg(new T);

                                auto_ptr<T> temp(new T);        

                                sg = temp;                                             

                       }

     

                       return sg;

                      

             }

    };

     

    // Singleton.cpp

    #include "Singleton.h"

     

    // 用下面的方式对静态私有成员变量sg进行初始化,此时sg不指向任何对象

    auto_ptr<Student> Singleton<Student>::sg;

     

    void getSingletonInstanceAndDoSomeTediousWork()

    {

             auto_ptr<Student> singleton(Singleton<Student>::getInstance());

     

             // 取得相关对象后,进行各种必要的运算:

             singleton->print_info();

             // .... do something else

     

             // 工作做完后,解锁。以便让别的线程获得机会。

             sglt_mutex.unlock();                                      // (2)

             // 如果没有上面这一句,则第一个获得锁的线程会无限时地阻止后续线程的运行

    }

     

    int main(void)

    {

             boost::thread threadA(getSingletonInstanceAndDoSomeTediousWork);

             boost::thread threadB(getSingletonInstanceAndDoSomeTediousWork);

             boost::thread threadC(getSingletonInstanceAndDoSomeTediousWork);

             boost::thread threadD(getSingletonInstanceAndDoSomeTediousWork);

     

             threadA.join();

             threadB.join();

             threadC.join();

             threadD.join();

     

             return 0;

    }

     

    上面程序的结果如下:

    Singleton::getInstance

    constructor...

    Name: Andrew, Age: 7

    Singleton::getInstance

    constructor...

    Name: Andrew, Age: 7

    Singleton::getInstance

    constructor...

    Name: Andrew, Age: 7

    Singleton::getInstance

    constructor...

    Name: Andrew, Age: 7

     

    上述结果符合预期。每次只能有一个线程,拥有对象,其他的则被阻塞,直到当前拥有锁的线程将锁解开。

     

    如果函数getSingletonInstanceAndDoSomeTediousWork中的语句(2)被注释掉,那么输出结果将是:

    Singleton::getInstance

    constructor...

    Name: Andrew, Age: 7

    然后就是无限时的阻塞。

     

    进一步地,如果将类Singelton定义中的(1)的这一句,即sglt_mutex.lock();也注释掉,那么输出的结果将是:

    Singleton::getInstanceSingleton::getInstanceSingleton::getInstance

     

    constructor...constructor...

    constructor...Name: Name: Name: AndrewName: AndrewAndrew, Age: Andrew, Age: , Age: 7, Age: 77

    这显然是没有同步了。因此,这不是我们所需要的。 

  • 相关阅读:
    hdu 2019 数列有序!
    hdu 2023 求平均成绩
    HDU 5805 NanoApe Loves Sequence (思维题) BestCoder Round #86 1002
    51nod 1264 线段相交
    Gym 100801A Alex Origami Squares (求正方形边长)
    HDU 5512 Pagodas (gcd)
    HDU 5510 Bazinga (字符串匹配)
    UVALive 7269 Snake Carpet (构造)
    UVALive 7270 Osu! Master (阅读理解题)
    UVALive 7267 Mysterious Antiques in Sackler Museum (判断长方形)
  • 原文地址:https://www.cnblogs.com/vimmer/p/2998808.html
Copyright © 2011-2022 走看看