单例模式之C++实现

来源:互联网 发布:解压缩软件64位 编辑:程序博客网 时间:2024/06/06 08:25

在软件开发中,有些资源通常只要生成一份,为了避免在程序中其他地方生成另外一份,或者生成另一份新的拷贝,必须在编码的时候利用语言编程技术来保证只会产生一份资源,而这样的编程技术称之为单例模式

根据单例的特点可以知道用C++来实现需要考虑的要点:

  1. 使得对象不能被拷贝、赋值;
  2. 所有的构造函数必须私有(这样就不会让 A a; A *p = new A; 通过编译);
  3. 但要保证在某处生成一个这样的对象;

第一条实现方式是通过把拷贝构造、拷贝赋值函数设为private类型;第二条实现方式跟第一条一样既把构造函数设为private类型;第三条貌似与第二条产生了冲突,确实如此,但可以通过友元的方式来实现。

首先来写一个Uncopyable类,大致如下:

class Uncopyable {    protected:        Uncopyable(){}        ~Uncopyable(){}    private:        /*         *  以下都只给出声明,这样的话如果在Uncopyable的成员函数或者是友元函数或类中方式拷         *  贝,则编译器在链接阶段会因为找不到定义而报错,同样阻止了这一类比较特别拷贝赋值操         *  作,当然这里主要是阻止 A a(b), A a=b,a=b 这种情况的发生(AUncopyable的派生类)         */        Uncopyable(const Uncopyable&);        const Uncopyable& operator=(const Uncopyable&);}

接着来写一个单例的模板父类:

tempalte<class T>class Singleton {    public:    static T * getInstance() {        static T instance;        return &instance;    }}

然后写一个用例,假设一个类A我只让它产生一个对象:

#include <iostream>using namespace std;class A: public Uncopyable {    friend class Singleton<A>;//使得类Singleton中可以调用所有A的私有构造函数    private:        A(){}        ... // 其他类型的构造函数};int main(){    A * a_ptr = Singleton<A>::getInstance();    cout << ( a_ptr == Singleton<A>::getInstance())<<endl; //编译通过,结果为1,也就是同一个指针    A b; //编译报错,提示A的构造函数私有    A c(*a_ptr);//编译错误,提示Uncopyable的拷贝构造函数是私有的    A d = *a_ptr;//同上,因为声明赋值同样是调用的拷贝构造函数    *a_ptr = *Singleton<A>::getInstance();//编译错误,提示operator=拷贝赋值函数为私有的    return 0;}

以上都是c++11环境下编译验证;

虽然上面的单例模式确实做到了基本功能,但是还是有些问题:
1. 返回指针容易使得程序猿无意识的 delete 这个指针;
2. 多线程不是安全;

先来看看解决1的一个方案:
把Singleton::getInstance 返回指针变成返回引用

    ...    static T & getInstance(){        static T instance;        return instance;    }    ...

在获取实例时则这么写:

    ...    A &a = Singleton<A>::getInstance();//这样的话应该没有程序猿会写 delete a这样的操作了把,即使写了,编译器也会提前告诉你    ...

第2个多线程问题,就是单例中的懒汉与饿汗两种模式了。说下大致思路把,饿汗了就是在程序启动阶段就初始化一个A的对象,以后不管多个线程直接取就是了,懒汉了当地第一次使用getInstance()才初始化一个A的对象,以后每次都是取第一次初始化的那个A对象。从这里就可以看出前面举的例子就是懒汉模式,懒汉模式的解决方法一般采用加锁的形式避免多线程竞争,而饿汗模式就不用考虑多线程问题。

下面来把上面的改成饿汗模式:
新加一个饿汗模式的单例类

template<class T>class SingletonEager{    public:        static T * getInstance(){            return instance;        }    private:        static T * instance;}template<class T>T * SingletonEager<T>::instance = new T;

而我们的类A也只需要改成如下即可:

class A:public Uncopyable{    friend class SingletonEager<A>;    private:        A(){}        ... //其他类型的构造函数}

其他情况请读者思考吧, 如有问题请大家指正……

1 0
原创粉丝点击