单例模式之C++实现

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

根据单例的特点可以知道用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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值