Singleton(一)

来源:互联网 发布:mac上可以玩的单机 编辑:程序博客网 时间:2024/06/05 17:19

1 用以支持 Singleton 的一些 C++ 几基本手法

// Header file Singleton.hclass Singleton{public:static Singleton* Instance(){if (!pInstance_)pInstance_ = new Singleton;return pInstance_;}private:Singleton();Singleton(const Singleton&);static Singleton* pInstance_;};// Implementation file Singleton.cppSingleton* Singleton::pInstance_ = 0;
问题:如果客户端(调用端)使用 delete 删除了 Singleton 怎么办?

// Header file Singleton.hclass Singleton{public:        // 传回引用而非指针避免客户端 delete Singleton 对象,这样比较安全些static Singleton& Instance(){if (!pInstance_)pInstance_ = new Singleton;return *pInstance_;}private:Singleton();Singleton(const Singleton&);static Singleton* pInstance_;};// Implementation file Singleton.cppSingleton* Singleton::pInstance_ = 0;

2 另一种方式构造 Singleton 

// Header file Singleton.hclass Singleton{public:static Singleton* Instance(){return &instance_;}        int Dosomething()        {        // ....        }private://....static Singleton instance_;};// Implementation file Singleton.cppSingleton Singleton::instance_;

问题:Singleton::instance_静态对象的初始化是否优先于使用者对象的调用?

// SomeFile.cpp#include "singleton.h"int global = Singleton::Instance()->Dosomething(); // 这时,Singleton::instance_对象已经初始化了吗?

面对不同编译单元(c++源文件)中动态初始化对象,C++并未定义其间的初始化顺序。

由于无法确保编译器一定先将instance_初始化,所以全局变量 global 的初值设定中对 Singleton::Instance的调用有可能传回一个尚未构造的对象。这意味着无法保证任何外部对象所使用的 instance_ 是一个已被正确初始化的对象。

3 保证 “Singleton的唯一性“

class Singleton{public:static Singleton& Instance();// unique point of access        //....private:Singleton();Singleton(const Singleton&);Singleton& operator=(const Singleton&);~Singleton();</strong>};

4 Singleton 应该在什么时候摧毁自身实体?

Singleton 未被删除,也不会造成内存泄露,因为singleton并非累积性数据,到进程结束仍然保存着一份实体。

然而,泄露是存在的,而且更隐蔽更有害,那就是资源泄露。这是因为 Singleton 构造函数可以索求广泛的资源:网络连接、OS互斥体和进程通讯方法中的各种handles等等。

避免资源泄露的唯一正确方法是在程序关闭时期删除 Singleton 对象。问题在于我们必须谨慎选择删除时机,确保 Singleton 对象被摧毁后不会再有任何人取用它。

// Meyers Singleton (由 Scott Meyers 最先提出)class Singleton{public:static Singleton& Instance() ){static Singleton obj; // 使用局部的静态变量,函数内的 static 对象在该函数第一次执行时被初始化(即执行期才初始化的 static 变量)return obj;}private:Singleton();Singleton(const Singleton&);Singleton& operator=(const Singleton&);~Singleton();};

 ”执行期才初始化“的 static 变量 和 ”通过编译器常量加以初始化“ 的基本型 static 变量的区别?

int Fun(){    static int x = 100; // 这是“通过编译期常量加以初始化”    return ++x;}
这种情况下 x 的初始化会在程序中的任何一行被执行之前完成,而且通常是在程序装在期间。 Fun() 第一次被调用前, x 早就被设为100了。如果初始值不是一个编译期常量,抑或静态变量是个拥有构造函数的对象,那么变量的初始化将发生于执行期,也就是跟第一次行经其定义式之时。

此外,编译器会产生一些代码,使得初始化之后,执行期相关机制会登记需被析构的变量(拥有构造函数的静态对象和全局对象)。这些代码的 C++ 伪代码看起来像下面这样:

static Singleton& Instance() {        // Functions generated by the compiler        extern void __ConstructSingleton(void* memory);        extern void __DestroySingleton();        // variable是generated by the compiler        static bool __initialized = false;        // Buffer that holds the singleton        // (We assume it is properly aligned)        static char __buffer[sizeof(Singleton)];        if (!__initialized)        {                // First call, construct object  // Will invoke Singleton::Singleton __ConstructSingleton(__buffer);// register destruction atexit(__DestroySingleton);__initialized = true;         }return *reinterpret_cast<Singleton*>(__Object);}
atexit 是由标准C 程序库提供,让你得以注册一些在程序结束之际自动被调用的的函数,且被调用次序为后进先出(LIFO。C++对象以LIFO方式进行,县产生的对象后摧毁你。当然,以 new 和 delete 管理的对象不遵守这一规则)。

编译器自动产生出 __DestroySingleton 函数(它被执行后会摧毁  __buffer 内存内的 Singleton 对象)并将其地址传给 atexit()。
atexit 函数的声明:int atexit(void (*pFun)());

atexit 如何运作? 每次被调用,它的参数会被压入 C runtime library 所维护的一个私有 stack 内。程序结束之际,执行期相关机制便会调用那些经由 atexit() 登记的函数。

Meyer singleton 提供的是"程序结束之际摧毁 Singleton"最简单的方式。

0 0
原创粉丝点击