C++之竹

无论是太阳下,还是风雨中,都要成长!

常用链接

统计

最新评论

Singleton模式——C++应用(一)

     前天,在看了《剑指Offer》中关于Singleton模式的一段内容后,就按耐不住对其在C++上完美实现的思考。书中这一讲是针对C#的实现来讲解的,因为C#的垃圾回收机制,其中那些个显眼的[new]已无需程序员去手动释放。但是,C++上确并不存在垃圾回收机制,程序员得手动[delete] [new]出来的内容,这就有了以下两问:
  1. 何时释放通过new所创建的Singleton对象?
  2. 如果不通过new、malloc等操作,是否能做到在第一次使用时才创建Singleton对象。

     在针对以上两个问题做了一番思考和尝试之后,终于有了成果。现呈现出来,供大家参考,也希望有更好妙招的朋友能不吝赐教。碍于连代码带文字,篇幅较长,所以我将分为四篇来讲。那么,开始咯!^_^

 

     一开始,我先拿使用静态成员变量的来实现的惰性单件来进行尝试,写了个Demo,一运行,O(∩_∩)O哈哈~,还真有意外的收获呢!嗯~,抓紧时间,先把我的Demo上来给大家瞧瞧!~

  1// Singleton demo_0: Singleton instance is a static member of class.
  2
  3#include <Windows.h>
  4#include <iostream>
  5
  6class A 
  7{
  8private:
  9    static A ms_instance;
 10
 11public:
 12    static A& GetInstance() {
 13        return ms_instance;
 14    }

 15
 16private:
 17    A() : m_nStat1(-1), m_nStat2(-1{
 18        m_nStat1 = 0;
 19        std::cout << "Construct A" << std::endl;
 20        m_nStat2 = 0;
 21    }

 22    A(const A&);
 23
 24public:
 25    ~A() {
 26        m_nStat1 = 0;
 27        std::cout << "Destruct A" << std::endl;
 28        m_nStat2 = 0;
 29    }

 30
 31    void Do() {
 32        ++m_nStat1;
 33        ++m_nStat2;
 34        std::cout << "Called Do() by object of A. [" 
 35                  << m_nStat1 << "" 
 36                  << m_nStat2 << "]" 
 37                  << std::endl;
 38    }

 39
 40private:
 41    int m_nStat1;
 42    int m_nStat2;
 43}
;
 44
 45class B
 46{
 47public:
 48    B(int nID) : m_nID(nID) {
 49        std::cout << "Construct B: " << m_nID << std::endl;
 50        A::GetInstance().Do();
 51    }

 52    ~B() {
 53        std::cout << "Destruct B: " << m_nID << std::endl;
 54        A::GetInstance().Do();
 55    }

 56
 57private:
 58    int m_nID;
 59}
;
 60
 61class C
 62{
 63private:
 64    static C ms_instance;
 65
 66public:
 67    static C& GetInstance() {
 68        return ms_instance;
 69    }

 70
 71private:
 72    C() : m_nStat(-1{
 73        std::cout << "Construct C" << std::endl;
 74        m_nStat = 0;
 75    }

 76    C(const C&);
 77
 78public:
 79    ~C() {
 80        std::cout << "Destruct C" << std::endl;
 81        m_nStat = 0;
 82    }

 83
 84    void Do() {
 85        ++m_nStat;
 86        std::cout << "Called Do() by object of C. [" 
 87            << m_nStat << "]" 
 88            << std::endl;
 89    }

 90
 91private:
 92    int m_nStat;
 93}
;
 94
 95static B gs_B0(0);
 96B g_B1(1);
 97A A::ms_instance;
 98C C::ms_instance;
 99static B gs_B2(2);
100B g_B3(3);
101
102int main(int argc, char * argv[])
103{
104    std::cout << "Enter main" << std::endl;
105    A::GetInstance().Do();
106    C::GetInstance().Do();
107
108    system("pause");
109    return 0;
110}

为了能够分析得细致些,Demo写得长了点,见谅咯!~

    嗯,对了,还有运行结果:

仔细看看结果,有没觉得这结果很出乎意料啊?!!(顺便提下,我用的编译工具是Visual C++ 2010)

从这个运行结果,对通过静态成员实现的惰性单件,我得到了以下两点:

  1. 对于定义在单件对象之前的全局或静态全局对象,虽然单件对象还是会在调用前及时构造,但构造函数内的初始化操作却可能在需要使用时还未能执行完全。
    如:std::cout 就会使得单件对象的构造函数调用被暂停(单件的其他操作还能继续调用),直到单件之前的全局或静态全局的构造函数全执行完了,才能继续执行。【*这个原因还请有知道的高手能赐教。
  2. 对于定义于单件对象之后的全局或静态全局对象,如果在析构中调用了单件,就会使得单件在释放后又被再次重新创建使用。当然,这时单件内所存的数据已跟之前毫无关联了。

因此,我要奉劝各位开发者,如果在你的全局或静态全局对象的构造或析构方法中调用某个单件,那么对该单件的实现就不要以静态成员来惰性地实现。

 

posted on 2012-03-12 02:04 青碧竹 阅读(272) 评论(0)  编辑 收藏 引用 所属分类: 设计模式


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理