设计模式之单例模式

73 篇文章 1 订阅
69 篇文章 0 订阅

Recently I've bumped into a realization/implementation of the Singleton design pattern for C++. It has looked like this (I have adopted it from the real life example):

// a lot of methods are omitted here
class Singleton
{
   public:
       static Singleton* getInstance( );
       ~Singleton( );
   private:
       Singleton( );
       static Singleton* instance;
};

From this declaration I can deduce that the instance field is initiated on the heap. That means there is a memory allocation. What is completely unclear for me is when exactly the memory is going to be deallocated? Or is there a bug and memory leak? It seems like there is a problem in the implementation.

My main question is, how do I implement it in the right way?

share improve this question
 
6 
8 
You'll find a great discussion of how to implement a singleton, along with thread-safety in C++ in this paper.aristeia.com/Papers/DDJ%5FJul%5FAug%5F2004%5Frevised.pdf –  Matthieu N.  Oct 30 '09 at 11:34
9 
Singletons are bad: jalf.dk/blog/2010/03/…. Don't use them. –  sbi  Jun 27 '11 at 10:33
41 
@sbi - Only a Sith deals in absolutes. Can the vast majority of problems be solved without Singletons? Absolutely. Do Singletons cause problems of their own? Yes. However, I can't honestly say that they'rebad, since design is all about considering the tradeoffs and understanding the nuances of your approach. –  derekerdmann  Jul 28 '11 at 20:10
7 
@derekerdmann: I didn't say you never need a global variable (and when you need one, a Singletonsometimes is better). What I said is that they should be used as little as possible. Glorifying Singleton as a valuable design pattern gives the impression it's good to use it, rather than that it is a hack, making code hard to understand, hard to maintain, and hard to test. This is why I posted my comment. None of what you said so far contradicted this. –  sbi  Jul 29 '11 at 13:26

15 Answers

up vote 487 down vote accepted

See this article for a simple design for a lazy evaluated with guaranteed destruction singleton:
Can any one provide me a sample of Singleton in c++?

The classic lazy evaluated and correctly destroyed singleton.

class S
{
    public:
        static S& getInstance()
        {
            static S    instance; // Guaranteed to be destroyed.
                                  // Instantiated on first use.
            return instance;
        }
    private:
        S() {};                   // Constructor? (the {} brackets) are needed here.

        // C++ 03
        // ========
        // Dont forget to declare these two. You want to make sure they
        // are unacceptable otherwise you may accidentally get copies of
        // your singleton appearing.
        S(S const&);              // Don't Implement
        void operator=(S const&); // Don't implement

        // C++ 11
        // =======
        // We can use the better technique of deleting the methods
        // we don't want.
        S(S const&)               = delete;
        void operator=(S const&)  = delete;

};

为什么需要单例模式       在很多项目中,我们可能都会遇到这样一种情况:某个类的对象在整个项目是唯一的,它不能也没必要被实例化多次,比如窗口管理器、皮肤加载器等等。这就催生出了如下的现实需求:如何确保某个类只有一个实例。

       在结构化程序设计方法中,我们可以使用全局变量来实现唯一实例,但它不能保证唯一性,因为它无法确保使用者不在其他的地方进行实例化。在面向对象程序设计方法中,我们有了更好的选择;我们可以通过将类的构造函数隐藏起来,以防止用户多次实例化对象,同时给用户提供一个获取该类实例的接口。这样就从类本身保证了对象的唯一性,防止了用户的误用。
什么是单例模式       单例模式,又称单件模式,是指在整个模块中,一个类只有一个实例。单例模式有“饿汉”式和“懒汉”式两种:所谓“饿汉”式,是指不管用户有没有使用该类的实例,它都会创建一个实例;所谓“懒汉”式,是指只有当用户初次使用该类的实例时,才会创建一个实例,而以后需要再次使用该类的实例时,直接返回初次创建的那个实例即可。在C++中,我们通常通过类的静态成员变量来实现单例模式。下面给出单例模式最原始的实现版本,暂且美其名曰原生态实现。
单例模式之原生态实现      Singleton1.h文件
 
Singleton1.cpp文件


上述代码很容易看懂。我们在静态成员函数Singleton中对静态成员变量m_pSingleton进行了判断,若为NULL,则创建一个对象;否则直接返回已创建的对象。另外,我们将构造函数和析构函数都声明成了protected类型的,这样就消除了用户在外部实例化对象的可能,保证了对象的唯一性。最后,由于我们是在堆上动态创建对象的,因此提供了一个静态成员函数Close用于最终释放这个动态创建的对象。
       仔细研究上述代码后,可以发现,这种实现方案中有一个静态成员函数Close,但却并没有提供对应的Open函数,单从接口对称方面来说,似乎并不美观。于是,我们便有了下面的单例模式之美学实现方案。单例模式之美学实现      Singleton2.h文件
    
Singleton2.cpp文件


在上述方案中,我们在静态成员函数Open中了进行了对象的创建工作,而静态成员函数Singleton完成的工作则相对简单,直接返回静态成员变量m_pSingleton即可。现在我们可以来看一下,如何使用该单例呢?需要先Open,然后调用Singleton,最后调用Close。很好,但这样是不是就完美了呢?对于追求极致的人来说,远非完美。如果我们可以不调用Open和Close,而只需直接调用Singleton,岂不是更好。这样既可以方便使用者,又可以避免误用和内存泄漏。这就需要我们自己来负责释放已经创建的唯一实例m_pSingleton。于是,我们又有了下面的单例模式之精简实现方案。单例模式之精简实现      Singleton3.h文件
    
    Singleton3.cpp文件
    该方案中的静态成员函数Singleton的实现与原生态方案中Singleton的实现完全一样,重点在于实现文件中声明的全局结构体变量term。在该结构体的析构函数中,我们做了原本需要在Close中完成的工作:释放已经创建的唯一实例。在该方案中值得注意的一点是,我们将析构函数变成了public的,这是由于我们需要在单例类外部释放已经创建的唯一实例,并且不想将结构体TSingleton3_Term暴露给用户。
现在好了,直接使用Singleton即可,不用Open,也不用Close,但该方案还存在一点瑕疵,就是没有考虑到默认的拷贝构造函数和赋值运算符。分析下面的代码,我们可以通过拷贝构造函数再创建一个对象,这显然破坏了单例模式的设计初衷。于是,单例模式之加强版实现应运而生。 
单例模式之加强版实现Singleton4.h文件


Singleton4.cpp文件


可以看到,该实现方案与精简实现方案几乎一样,只不过它将拷贝构造函数和赋值运算符隐藏了起来,以防止用户在外部构造对象。至此,我们的单例类似乎已经很完善了,但如果我们设身处地地为用户想一下,可以发现,每次设计一个单例类时,都需要编写那些几乎一模一样的Open、Singleton和Close函数,这对于那些懒惰的软件开发人员来说,简直是不可忍受的。幸好,我们还有泛型编程,于是,我们有了如下的单例模式之模板实现(仅给出模板精简版实现)。单例模式之模板实现      Singleton5.h文件
  
懂得泛型编程的人应当不难理解上述代码,所以这里就不再赘述了。那么,如何使用这个模板类呢?只需将我们需要设置成单例模式的类从其派生即可。下面给出一个派生类的具体实现。
DerivedSingleton5.h文件


DerivedSingleton5.cpp文件


在该派生类中,我们将模板类作为其友元类,这是因为在模板类的Singleton函数中,需要调用派生类的构造函数。总结       以上一共给出了单例模式的5种实现方案,给出这些方案的主要目的并不在于比较哪个方案更好,而是展现一种思考问题的方式和思路。懂得如何思考一个问题,可能比解决一个问题更有价值,更有助于我们成长。
-- 本文来源于创世软件团队博客, 原文地址: http://www.cnblogs.com/hujian/archive/2010/12/15/1906503.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值